Lean 4.20.0 (2025-06-02)
For this release, 346 changes landed. In addition to the 108 feature additions and 85 fixes listed below there were 6 refactoring changes, 7 documentation improvements, 8 performance improvements, 4 improvements to the test suite and 126 other changes.
Highlights
The Lean v4.20.0 release brings multiple new features, bug fixes, improvements to Lake, and groundwork for the module system.
Language Features
-
#6432 implements tactics called
extract_letsandlift_letsthat manipulatelet/let_funexpressions. Theextract_letstactic creates new local declarations extracted from anyletandlet_funexpressions in the main goal. For top-level lets in the target, it is like theintrostactic, but in general it can extract lets from deeper subexpressions as well. Thelift_letstactic movesletandlet_funexpressions as far out of an expression as possible, but it does not extract any new local declarations. The optionextract_lets +liftcombines these behaviors. -
#7806 modifies the syntaxes of the
ext,introandenterconv tactics to accept_. The introduced binder is an inaccessible name. -
#7830 modifies the syntax of
induction,cases, and other tactics that useLean.Parser.Tactic.inductionAlts. If a case omits=> ...then it is assumed to be=> ?_. Example:example (p : Nat × Nat) : p.1 = p.1 := by cases p with | _ p1 p2 /- case mk p1 p2 : Nat ⊢ (p1, p2).fst = (p1, p2).fst -/
This works with multiple cases as well. Example:
example (n : Nat) : n + 1 = 1 + n := by induction n with | zero | succ n ih /- case zero ⊢ 0 + 1 = 1 + 0 case succ n : Nat ih : n + 1 = 1 + n ⊢ n + 1 + 1 = 1 + (n + 1) -/
The
induction n with | zero | succ n ihis short forinduction n with | zero | succ n ih => ?_, which is short forinduction n with | zero => ?_ | succ n ih => ?_. Note that a consequence of parsing is that only the last alternative can omit=>. Any=>-free alternatives before an alternative with=>will be a part of that alternative. -
#7831 adds extensibility to the
evalAndSuggestprocedure used to implementtry?. Users can now implement their own handlers for any tactic.-- Install a `TryTactic` handler for `assumption` @[try_tactic assumption] def evalTryApply : TryTactic := fun tac => do -- We just use the default implementation, but return a different tactic. evalAssumption tac `(tactic| (trace "worked"; assumption)) /-- info: Try this: · trace "worked"; assumption -/ #guard_msgs (info) in example (h : False) : False := by try? (max := 1) -- at most one solution -- `try?` uses `evalAndSuggest` the attribute `[try_tactic]` is used to extend `evalAndSuggest`. -- Let's define our own `try?` that uses `evalAndSuggest` elab stx:"my_try?" : tactic => do -- Things to try let toTry ← `(tactic| attempt_all | assumption | apply True | rfl) evalAndSuggest stx toTry /-- info: Try these: • · trace "worked"; assumption • rfl -/ #guard_msgs (info) in example (a : Nat) (h : a = a) : a = a := by my_try?
-
#8055 adds an implementation of an async IO multiplexing framework as well as an implementation of it for the
TimerAPI in order to demonstrate it. -
#8088 adds the “unfolding” variant of the functional induction and functional cases principles, under the name
foo.induct_unfoldingresp.foo.fun_cases_unfolding. These theorems combine induction over the structure of a recursive function with the unfolding of that function, and should be more reliable, easier to use and more efficient than just case-splitting and then rewriting with equational theorems.For example instead of
ackermann.induct (motive : Nat → Nat → Prop) (case1 : ∀ (m : Nat), motive 0 m) (case2 : ∀ (n : Nat), motive n 1 → motive (Nat.succ n) 0) (case3 : ∀ (n m : Nat), motive (n + 1) m → motive n (ackermann (n + 1) m) → motive (Nat.succ n) (Nat.succ m)) (x x : Nat) : motive x x
one gets
ackermann.fun_cases_unfolding (motive : Nat → Nat → Nat → Prop) (case1 : ∀ (m : Nat), motive 0 m (m + 1)) (case2 : ∀ (n : Nat), motive n.succ 0 (ackermann n 1)) (case3 : ∀ (n m : Nat), motive n.succ m.succ (ackermann n (ackermann (n + 1) m))) (x✝ x✝¹ : Nat) : motive x✝ x✝¹ (ackermann x✝ x✝¹)
-
#8097 adds support for inductive and coinductive predicates defined using lattice theoretic structures on
Prop. These are syntactically defined usinggreatest_fixpointorleast_fixpointtermination clauses for recursiveProp-valued functions. The functionality relies onpartial_fixpointmachinery and requires function definitions to be monotone. For non-mutually recursive predicates, an appropriate (co)induction proof principle (given by Park induction) is generated.
Library Highlights
#8004 adds extensional hash maps and hash sets under the names
Std.ExtDHashMap, Std.ExtHashMap and Std.ExtHashSet. Extensional
hash maps work like regular hash maps, except that they have
extensionality lemmas which make them easier to use in proofs. This
however makes it also impossible to regularly iterate over its entries.
Other notable library developments in this release include:
-
Updates to the
OptionAPI, -
Async runtime developments: added support for multiplexing via UDP and TCP sockets, as well as channels,
-
New
BitVecdefinitions related to overflow handling, -
New lemmas for
Nat.lcm, andIntvariants forNat.gcdandNat.lcm, -
Upstreams from Mathlib related to
NatandInt, -
Additions to numeric types APIs, such as
UIntX.ofInt,Fin.ofNat'_mulandFin.mul_ofNat',Int.toNat_sub'', -
Updates to
PermAPI inArray,List, and added support forVector, -
Additional lemmas for
Array/List/Vector.
Lake
-
#7909 adds Lake support for building modules given their source file path. This is made use of in both the CLI and the server.
Breaking Changes
-
#7474 updates
rw?,show_term, and other tactic-suggesting tactics to suggestexpose_nameswhen necessary and validate tactics prior to suggesting them, asexact?already did, and it also ensures all such tactics produce hover info in the messages showing tactic suggestions.This introduces a breaking change in the
TryThisAPI: thetype?parameter ofaddRewriteSuggestionis now anLOption, not anOption, to obviate the need for a hack we previously used to indicate that a rewrite closed the goal. -
#7789 fixes
leanpotentially changing or interpreting arguments after--run.Breaking change: The Lean file to run must now be passed directly after
--run, which accidentally was not enforced before. -
#7813 fixes an issue where
let n : Nat := sorryin the Infoview pretty prints asn : ℕ := sorry `«Foo:17:17». This was caused by top-level expressions being pretty printed with the same rules as Infoview hovers. Closes #6715. RefactorsLean.Widget.ppExprTagged; now it takes a delaborator, and downstream users should configure their own pretty printer option overrides if necessary if they used theexplicitargument (seeLean.Widget.makePopup.ppExprForPopupfor an example). Breaking change:ppExprTaggeddoes not setpp.proofson the root expression. -
#7855 moves
ReflBEqtoInit.Coreand changesLawfulBEqto extendReflBEq.Breaking changes:
-
The
reflfield ofReflBEqhas been renamed torflto matchLawfulBEq -
LawfulBEqextendsReflBEq, so in particularLawfulBEq.rflis no longer valid
-
-
#7873 fixes a number of bugs related to the handling of the source search path in the language server, where deleting files could cause several features to stop functioning and both untitled files and files that don't exist on disc could have conflicting module names.
See the PR description for the details on changes in URI <-> module name conversion.
Breaking changes:
-
Server.documentUriFromModulehas been renamed toServer.documentUriFromModule?and doesn't take aSearchPathargument anymore, as theSearchPathis now computed from theLEAN_SRC_PATHenvironment variable. It has also been moved fromLean.Server.GoTotoLean.Server.Utils. -
Server.moduleFromDocumentUridoes not take aSearchPathargument anymore and won't return anOptionanymore. It has also been moved fromLean.Server.GoTotoLean.Server.Utils. -
The
System.SearchPath.searchModuleNameOfUrifunction has been removed. It is recommended to useServer.moduleFromDocumentUriinstead. -
The
initSrcSearchPathfunction has been renamed togetSrcSearchPathand has been moved fromLean.Util.PathstoLean.Util.Path. It also doesn't need to take apkgSearchPathargument anymore.
-
-
#7967 adds a
bootstrapoption to Lake which is used to identify the core Lean package. This enables Lake to use the current stage's include directory rather than the Lean toolchains when compiling Lean with Lean in core.Breaking change: The Lean library directory is no longer part of
getLeanLinkSharedFlags. FFI users should provide this option separately when linking to Lean (e.g.. vias!"-L{(←getLeanLibDir).toString}"). See the FFI example for a demonstration.
Language
-
#6325 ensures that environments can be loaded, repeatedly, without executing arbitrary code
-
#6432 implements tactics called
extract_letsandlift_letsthat manipulatelet/let_funexpressions. Theextract_letstactic creates new local declarations extracted from anyletandlet_funexpressions in the main goal. For top-level lets in the target, it is like theintrostactic, but in general it can extract lets from deeper subexpressions as well. Thelift_letstactic movesletandlet_funexpressions as far out of an expression as possible, but it does not extract any new local declarations. The optionextract_lets +liftcombines these behaviors. -
#7474 updates
rw?,show_term, and other tactic-suggesting tactics to suggestexpose_nameswhen necessary and validate tactics prior to suggesting them, asexact?already did, and it also ensures all such tactics produce hover info in the messages showing tactic suggestions. -
#7797 adds a monolithic
CommRingclass, for internal use bygrind, and includes instances forInt/BitVec/IntX/UIntX. -
#7803 adds normalization rules for function composition to
grind. -
#7806 modifies the syntaxes of the
ext,introandenterconv tactics to accept_. The introduced binder is an inaccessible name. -
#7808 adds missing forall normalization rules to
grind. -
#7816 fixes an issue where
x.f.gwouldn't work but(x.f).gwould whenx.fis generalized field notation. The problem was thatx.f.gwould assumex : Tshould be the first explicit argument toT.f. Now it uses consistent argument insertion rules. Closes #6400. -
#7825 improves support for
Natin thecutsatprocedure used ingrind:-
cutsatno longer pollutes the local context with facts of the form-1 * NatCast.natCast x <= 0for eachx : Nat. These facts are now stored internally in thecutsatstate. -
A single context is now used for all
Natterms.
-
-
#7829 fixes an issue in the cutsat counterexamples. It removes the optimization (
Cutsat.State.terms) that was used to avoid the new theoremeq_def. In the two new tests, prior to this PR,cutsatproduced a bogus counterexample withb := 2. -
#7830 modifies the syntax of
induction,cases, and other tactics that useLean.Parser.Tactic.inductionAlts. If a case omits=> ...then it is assumed to be=> ?_. Example:example (p : Nat × Nat) : p.1 = p.1 := by cases p with | _ p1 p2 /- case mk p1 p2 : Nat ⊢ (p1, p2).fst = (p1, p2).fst -/
This works with multiple cases as well. Example:
example (n : Nat) : n + 1 = 1 + n := by induction n with | zero | succ n ih /- case zero ⊢ 0 + 1 = 1 + 0 case succ n : Nat ih : n + 1 = 1 + n ⊢ n + 1 + 1 = 1 + (n + 1) -/
The
induction n with | zero | succ n ihis short forinduction n with | zero | succ n ih => ?_, which is short forinduction n with | zero => ?_ | succ n ih => ?_. Note that a consequence of parsing is that only the last alternative can omit=>. Any=>-free alternatives before an alternative with=>will be a part of that alternative. -
#7831 adds extensibility to the
evalAndSuggestprocedure used to implementtry?. Users can now implement their own handlers for any tactic. The new test demonstrates how this feature works. -
#7859 allows the LRAT parser to accept any proof that derives the empty clause at somepoint, not necessarily in the last line. Some tools like lrat-trim occasionally include deletions after the derivation of the empty clause but the proof is sound as long as it soundly derives the empty clause somewhere.
-
#7861 fixes an issue that prevented theorems from being activated in
grind. -
#7862 improves the normalization of
Boolterms ingrind. Recall thatgrindcurrently does not case split on Boolean terms to reduce the size of the search space. -
#7864 adds support to
grindfor case splitting on implications of the formp -> qand(h : p) -> q h. See the new option(splitImp := true). -
#7865 adds a missing propagation rule for implication in
grind. It also avoids unnecessary case-splits on implications. -
#7870 adds a mixin typeclass for
Lean.Grind.CommRingrecording the characteristic of the ring, and constructs instances forInt,IntX,UIntX, andBitVec. -
#7885 fixes the counterexamples produced by the cutsat procedure in
grindfor examples containingNatterms. -
#7892 improves the support for
funextingrind. We will push another PR to minimize the number of case-splits later. -
#7902 introduces a dedicated option for checking whether elaborators are running in the language server.
-
#7905 fixes an issue introduced bug #6125 where an
inductiveorstructurewith an autoimplicit parameter with a type that has a metavariable would lead to a panic. Closes #7788. -
#7907 fixes two bugs in
grind.-
Model-based theory combination was creating type incorrect terms.
-
Nat.castvsNatCast.natCastissue during normalization.
-
-
#7914 adds a function hook
PersistentEnvExtension.saveEntriesFnthat can be used to store server-only metadata such as position information and docstrings that should not affect (re)builds. -
#7920 introduces a fast path based on comparing the (cached) hash value to the
DecidableEqinstance of the core expression data type inbv_decide's bitblaster. -
#7926 fixes two issues that were preventing
grindto solvegetElem?_eq_some_iff.-
Missing propagation rule for
Exists p = False -
Missing conditions at
isCongrToPrevSplita filter for discarding unnecessary case-splits.
-
-
#7937 implements a lookahead feature to reduce the size of the search space in
grind. It is currently effective only for arithmetic atoms. -
#7949 adds the attribute
[grind ext]. It is used to select which[ext]theorems should be used bygrind. The optiongrind +extAllinstructsgrindto use all[ext]theorems available in the environment. After update stage0, we need to add the builtin[grind ext]annotations to key theorems such asfunext. -
#7950 modifies
all_goalsso that in recovery mode it commits changes to the state only for those goals for which the tactic succeeds (while preserving the new message log state). Before, we were trusting that failing tactics left things in a reasonable state, but now we roll back and admit the goal. The changes also fixes a bug where we were rolling back only the metacontext state and not the tactic state, leading to an inconsistent state (a goal list with metavariables not in the metacontext). Closes #7883 -
#7952 makes two improvements to the local context when there are autobound implicits in
variables. First, the local context no longer has two copies of every variable (the local context is rebuilt if the types of autobound implicits have metavariables). Second, these metavariables get names using the same algorithm used by binders that appear in declarations (withmkForallFVars'instead ofmkForallFVars). -
#7957 ensures that
mkAppMcan be used to construct terms that are only type-correct at at default transparency, even if we are inwithReducible(e.g. in simp), so that simp does not stumble over simplifyingletexpression with simplifiable type.reliable. -
#7961 fixes a bug in bv_decide where if it was presented with a match on an enum with as many arms as constructors but the last arm being a default match it would (wrongly) give up on the match.
-
#7975 reduces the priority of the parent projections of
Lean.Grind.CommRing, to avoid these being used in typeclass inference in Mathlib. -
#7976 ensure that
bv_decidecan handle the simp normal form of a shift. -
#7978 adds a repro for a non-determinism problem in
grind. -
#7980 adds a simple type for representing monomials in a
CommRing. This is going to be used ingrind. -
#7986 implements reverse lexicographical and graded reverse lexicographical orders for
CommRingmonomials. -
#7989 adds functions and theorems for
CommRingmultivariate polynomials. -
#7992 add a function for converting
CommRingexpressions into multivariate polynomials. -
#7997 removes all type annotations (optional paramters, auto parameters, out params, semi-out params, not just optional parameters as before) from the type of functional induction principles.
-
#8011 adds
IsCharPsupport to the multivariate‑polynomial library inCommRing. -
#8012 adds the option
debug.terminalTacticsAsSorry. When enabled, terminal tactics such asgrindandomegaare replaced withsorry. Useful for debugging and fixing bootstrapping issues. -
#8014 makes
RArrayuniverse polymorphic. -
#8016 fixes several issues in the
CommRingmultivariate polynomial library:-
Replaces the previous array type with the universe polymorphic
RArray. -
Properly eliminates cancelled monomials.
-
Sorts monomials in decreasing order.
-
Marks the parameter
pof theIsCharPclass as an output parameter. -
Adds
LawfulBEqinstances for the typesPower,Mon, andPoly.
-
-
#8025 simplifies the
CommRingmonomials, and adds-
Monomial
lcm -
Monomial division
-
S-polynomials
-
-
#8029 implements basic support for
CommRingingrind. Terms are already being reified and normalized. We still need to process the equations, butgrindcan already prove simple examples such as:open Lean.Grind in example [CommRing α] (x : α) : (x + 1)*(x - 1) = x^2 - 1 := by grind +ring
-
#8032 adds support to
grindfor detecting unsatisfiable commutative ring equations when the ring characteristic is known. Examples:example (x : Int) : (x + 1)*(x - 1) = x^2 → False := by grind +ring
-
#8033 adds functions for converting
CommRingreified terms back into Lean expressions. -
#8036 fixes a linearity issue in
bv_decide's bitblaster, caused by the fact that the higher order combinatorsAIG.RefVec.zipandAIG.RefVec.foldwere not being properly specialised. -
#8042 makes
IntCasta field ofLean.Grind.CommRing, along with additional axioms relating it to negation ofOfNat. This allows use to use existing instances which are not definitionally equal to the previously given construction. -
#8043 adds
NullCerttype for representing Nullstellensatz certificates that will be produced by the new commutative ring procedure ingrind. -
#8050 fixes missing trace messages when produced inside
realizeConst -
#8055 adds an implementation of an async IO multiplexing framework as well as an implementation of it for the
TimerAPI in order to demonstrate it. -
#8064 adds a failing
grindtest, showing a bug where grind is trying to assign a metavariable incorrectly. -
#8065 adds a (failing) test case for an obstacle I've been running into setting up
grindforHashMap. -
#8068 ensures that for modules opted into the experimental module system, we do not import module docstrings or declaration ranges.
-
#8076 fixes
simp?!,simp_all?!anddsimp?!to do auto-unfolding. -
#8077 adds simprocs to simplify appends of non-overlapping Bitvector adds. We add a simproc instead of just a
simplemma to ensure that we correctly rewrite bitvector appends. Since bitvector appends lead to computation at the bitvector width level, it seems to be more stable to write a simproc. -
#8083 fixes #8081.
-
#8086 makes sure that the functional induction priciples for mutually recursive structural functions with extra parameters are split deeply, as expected.
-
#8088 adds the “unfolding” variant of the functional induction and functional cases principles, under the name
foo.induct_unfoldingresp.foo.fun_cases_unfolding. These theorems combine induction over the structure of a recursive function with the unfolding of that function, and should be more reliable, easier to use and more efficient than just case-splitting and then rewriting with equational theorems. -
#8090 adjusts the experimental module system to elide theorem bodies (i.e. proofs) from being imported into other modules.
-
#8094 fixes the generation of functional induction principles for functions with nested nested well-founded recursion and late fixed parameters. This is a follow-up for #7166. Fixes #8093.
-
#8096 lets
inductionaccept eliminator where the motive application in the conclusion has complex arguments; these are abstracted over usingkabstractif possible. This feature will go well with unfolding induction principles (#8088). -
#8097 adds support for inductive and coinductive predicates defined using lattice theoretic structures on
Prop. These are syntactically defined usinggreatest_fixpointorleast_fixpointtermination clauses for recursiveProp-valued functions. The functionality relies onpartial_fixpointmachinery and requires function definitions to be monotone. For non-mutually recursive predicates, an appropriate (co)induction proof principle (given by Park induction) is generated. -
#8101 fixes a parallelism regression where linters that e.g. check for errors in the command would no longer find such messages.
-
#8102 allows ASCII
<-inif letclauses, for consistency with bind, where both are allowed. Fixes #8098. -
#8111 adds the helper type class
NoZeroNatDivisorsfor the commutative ring procedure ingrind. Core only implements it forInt. It can be instantiated in Mathlib for any typeAthat implementsNoZeroSMulDivisors Nat A. SeefindSimp?andPolyDerivationfor details on how this instance impacts the commutative ring procedure. -
#8122 implements the generation of compact proof terms for Nullstellensatz certificates in the new commutative ring procedure in
grind. Some examples:example [CommRing α] (x y : α) : x = 1 → y = 2 → 2*x + y = 4 := by grind +ring
-
#8126 implements the main loop of the new commutative ring procedure in
grind. In the main loop, for each polynomialpin the todo queue, the procedure:-
Simplifies it using the current basis.
-
Computes critical pairs with polynomials already in the basis and adds them to the queue.
-
-
#8128 implements equality propagation in the new commutative ring procedure in
grind. The idea is to propagate implied equalities back to thegrindcore module that does congruence closure. In the following example, the equalities:x^2*y = 1andx*y^2 - y = 0imply thaty*xis equal toy*x*y, which implies by congruence thatf (y*x) = f (y*x*y).example [CommRing α] (x y : α) (f : α → Nat) : x^2*y = 1 → x*y^2 - y = 0 → f (y*x) = f (y*x*y) := by grind +ring
-
#8129 updates the If-Normalization example, to separately give an implementation and subsequently prove the spec (using fun_induction), instead of previously building a term in the subtype directly. At the same time, adds a (failing)
grindtest case illustrating a problem with unused match witnesses. -
#8131 adds a configuration option that controls the maximum number of steps the commutative-ring procedure in
grindperforms. -
#8133 fixes the monomial order used by the commutative ring procedure in
grind. The following new test now terminates quickly.example [CommRing α] (a b c : α) : a + b + c = 3 → a^2 + b^2 + c^2 = 5 → a^3 + b^3 + c^3 = 7 → a^4 + b^4 + c^4 = 9 := by grind +ring -
#8134 ensures that
set_option grind.debug trueworks properly when usinggrind +ring. It also adds the helper functionsmkPropEqandmkExpectedPropHint. -
#8137 improves equality propagation (also known as theory combination) and polynomial simplification for rings that do not implement the
NoZeroNatDivisorsclass. With these fixes,grindcan now solve:example [CommRing α] (a b c : α) (f : α → Nat) : a + b + c = 3 → a^2 + b^2 + c^2 = 5 → a^3 + b^3 + c^3 = 7 → f (a^4 + b^4) + f (9 - c^4) ≠ 1 := by grind +ringThis example uses the commutative ring procedure, the linear integer arithmetic solver, and congruence closure. For rings that implement
NoZeroNatDivisors, a polynomial is now also divided by the greatest common divisor (gcd) of its coefficients when it is inserted into the basis. -
#8157 fixes an incompatibility of
replayConstas used by e.g.aesopwithnative_decide-using tactics such asbv_decide -
#8158 fixes the
grind +splitImpand the arrow propagator. Givenp : Prop, the propagator was incorrectly assumingAwas always a proposition in an arrowA -> p. also adds a missing normalization rule togrind. -
#8159 adds support for the following import variants to the experimental module system:
-
private import: Makes the imported constants available only in non-exported contexts such as proofs. In particular, the import will not be loaded, or required to exist at all, when the current module is imported into other modules. -
import all: Makes non-exported information such as proofs of the imported module available in non-exported contexts in the current module. Main purpose is to allow for reasoning about imported definitions when they would otherwise be opaque. TODO: adjust name resolution so that importedprivatedecls are accessible through syntax.
-
-
#8161 changes
Lean.Grind.CommRingto inline theNatCastinstance (i.e. to be provided by the user) rather than constructing one from the existing data. Without this change we can't construct instances in Mathlib thatgrindcan use. -
#8163 adds some currently failing tests for
grind +ring, resulting in either kernel type mismatches (bugs) or a kernel deep recursion (perhaps just a too-large problem). -
#8167 improves the heuristics used to compute the basis and simplify polynomials in the commutative procedure used in
grind. -
#8168 fixes a bug when constructing the proof term for a Nullstellensatz certificate produced by the new commutative ring procedure in
grind. The kernel was rejecting the proof term. -
#8170 adds the infrastructure for creating stepwise proof terms in the commutative procedure used in
grind. -
#8189 implements stepwise proof terms in the commutative ring procedure used by
grind. These terms serve as an alternative representation to the traditional Nullstellensatz certificates, aiming to address the exponential worst-case complexity often associated with certificate construction. -
#8231 changes the behaviour of
apply?so that thesorryit uses to close the goal is non-synthetic. (Recall that correct use of synthetic sorries requires that the tactic also generates an error message, which we don't want to do in this situation.) Either this PR or #8230 are sufficient to defend against the problem reported in #8212. -
#8254 fixes unintended inlining of
ToJson,FromJson, andReprinstances, which was causing exponential compilation times inderivingclauses for large structures.
Library
-
#6081 adds an
inheritEnvfield toIO.Process.SpawnArgs. Iffalse, the spawned process does not inherit its parent's environment. -
#7108 proves
List.head_of_mem_head?and the analogousList.getLast_of_mem_getLast?. -
#7400 adds lemmas for the
filter,mapandfilterMapfunctions of the hash map. -
#7659 adds SMT-LIB operators to detect overflow
BitVec.(umul_overflow, smul_overflow), according to the definitions here, and the theorems proving equivalence of such definitions with theBitVeclibrary functions (umulOverflow_eq,smulOverflow_eq). Support theorems for these proofs areBitVec.toInt_one_of_lt, BitVec.toInt_mul_toInt_lt, BitVec.le_toInt_mul_toInt, BitVec.toNat_mul_toNat_lt, BitVec.two_pow_le_toInt_mul_toInt_iff, BitVec.toInt_mul_toInt_lt_neg_two_pow_iffandInt.neg_mul_le_mul, Int.bmod_eq_self_of_le_mul_two, Int.mul_le_mul_of_natAbs_le, Int.mul_le_mul_of_le_of_le_of_nonneg_of_nonpos, Int.pow_lt_pow. The PR also includes a set of tests. -
#7671 contains the theorem proving that signed division x.toInt / y.toInt only overflows when
x = intMin wandy = allOnes w(for0 < w). To show that this is the only case in which overflow happens, we refer to overflow for negation (BitVec.sdivOverflow_eq_negOverflow_of_neg_one): in fact,x.toInt/(allOnes w).toInt = - x.toInt, i.e., the overflow conditions are the same asnegOverflowforx, and then reason about the signs of the operands with the respective theorems. These BitVec theorems themselves rely on numerousInt.ediv_*theorems, that carefully set the bounds of signed division for integers. -
#7761 implements the core theorem for the Bitwuzla rewrites NORM_BV_NOT_OR_SHL and BV_ADD_SHL, which convert the mixed-boolean-arithmetic expression into a purely arithmetic expression:
theorem add_shiftLeft_eq_or_shiftLeft {x y : BitVec w} : x + (y <<< x) = x ||| (y <<< x) -
#7770 adds a shared mutex (or read-write lock) as
Std.SharedMutex. -
#7774 adds
Option.pfilter, a variant ofOption.filterand several lemmas for it and otherOptionfunctions. These lemmas are split off from #7400. -
#7791 adds lemmas about
Nat.lcm. -
#7802 adds
Int.gcdandInt.lcmvariants of allNat.gcdandNat.lcmlemmas. -
#7818 deprecates
Option.mergeandOption.liftOrGetin favor ofOption.zipWith. -
#7819 extends
Std.Channelto provide a full sync and async API, as well as unbounded, zero sized and bounded channels. -
#7835 adds
BitVec.[toInt_append|toFin_append]. -
#7847 removes
@[simp]from all deprecated theorems.simpwill still use such lemmas, without any warning message. -
#7851 partially reverts #7818, because the function called
Option.zipWithin that PR does not actually correspond toList.zipWith. We chooseOption.mergeas the name instead. -
#7855 moves
ReflBEqtoInit.Coreand changesLawfulBEqto extendReflBEq. -
#7856 changes definitions and theorems not to use the membership instance on
Optionunless the theorem is specifically about the membership instance. -
#7869 fixes a regression introduced in #7445 where the new
Array.emptyWithCapacitywas accidentally not tagged with the correct function to actually allocate the capacity. -
#7871 generalizes the typeclass assumptions on monadic
Optionfunctions. -
#7879 adds
Int.toNat_emod, analogous toInt.toNat_add/mul. -
#7880 adds the functions
UIntX.ofInt, and basic lemmas. -
#7886 adds
UIntX.powandPow UIntX Natinstances, and similarly for signed fixed-width integers. These are currently only the naive implementation, and will need to be subsequently replaced via@[extern]with fast implementations (tracked at #7887). -
#7888 adds
Fin.ofNat'_mulandFin.mul_ofNat', parallel to the existing lemmas aboutadd. -
#7889 adds
Int.toNat_sub''a variant ofInt.toNat_subtaking inequality hypotheses, rather than expecting the arguments to be casts of natural numbers. This is parallel to the existingtoNat_addandtoNat_mul. -
#7890 adds missing lemmas about
Int.bmod, parallel to lemmas about the othermodvariants. -
#7891 adds the rfl simp lemma
Int.cast x = xforx : Int. -
#7893 adds
BitVec.powandPow (BitVec w) Nat. The implementation is the naive one, and should later be replaced by an@[extern]. This is tracked at https://github.com/leanprover/lean4/issues/7887. -
#7897 cleans up the
Optiondevelopment, upstreaming some results from mathlib in the process. -
#7899 shuffles some results about integers around to make sure that all material that currently exists about
Int.bmodis located inDivMod/Lemmas.leanand not downstream of that. -
#7901 adds
instance [Pure f] : Inhabited (OptionT f α), so thatInhabited (OptionT Id Empty)synthesizes. -
#7912 adds
List.Perm.take/drop, andArray.Perm.extract, restricting permutations to sublist / subarrays when they are constant elsewhere. -
#7913 adds some missing
List/Array/Vector lemmasaboutisSome_idxOf?,isSome_finIdxOf?,isSome_findFinIdx?,isSome_findIdx?and the correspondingisNone` versions. -
#7933 adds lemmas about
Int.bmodto achieve parity betweenInt.bmodandInt.emod/Int.fmod/Int.tmod. Furthermore, it adds missing lemmas foremod/fmod/tmodand performs cleanup on names and statements for all four operations, also with a view towards increasing consistency with the correspondingNat.modlemmas. -
#7938 adds lemmas about
List/Array/Vector.countP/countinteracting withreplace. (Specializing to_selfand_nelemmas doesn't seem useful, as there will still be anifon the RHS.) -
#7939 adds
Array.count_eraseand specializations. -
#7953 generalizes some typeclass hypotheses in the
List.PermAPI (away fromDecidableEq), and reproducesList.Perm.mem_iffforArray, and fixes a mistake in the statement ofArray.Perm.extract. -
#7971 upstreams much of the material from
Mathlib/Data/Nat/Init.leanandMathlib/Data/Nat/Basic.lean. -
#7983 upstreams many of the results from
Mathlib/Data/Int/Init.lean. -
#7994 reproduces the
Array.PermAPI forVector. Both are still significantly less developed than the API forList.Perm. -
#7999 replaces
Array.PermandVector.Permwith one-field structures. This avoids dot notation forListto work like e.g.h.cons 3wherehis anArray.Perm. -
#8000 deprecates some
Int.ofNat_*lemmas in favor ofInt.natCast_*. -
#8004 adds extensional hash maps and hash sets under the names
Std.ExtDHashMap,Std.ExtHashMapandStd.ExtHashSet. Extensional hash maps work like regular hash maps, except that they have extensionality lemmas which make them easier to use in proofs. This however makes it also impossible to regularly iterate over its entries. -
#8030 adds some missing lemmas about
List/Array/Vector.findIdx?/findFinIdx?/findSome?/idxOf?. -
#8044 introduces the modules
Std.Data.DTreeMap.Raw,Std.Data.TreeMap.RawandStd.Data.TreeSet.Rawand imports them intoStd.Data. All modules related to the raw tree maps are imported into these new modules so that they are now a transitive dependency ofStd. -
#8067 fixes the behavior of
Substring.isNatto disallow empty strings. -
#8078 is a follow up to #8055 and implements a
Selectorfor async TCP in order to allow IO multiplexing using TCP sockets. -
#8080 fixes
Json.parseto handle surrogate pairs correctly. -
#8085 moves the coercion
α → Option αto the new fileInit.Data.Option.Coe. This file may not be imported anywhere inInitorStd. -
#8089 adds optimized division functions for
IntandNatwhen the arguments are known to be divisible (such as when normalizing rationals). These are backed by the gmp functionsmpz_divexactandmpz_divexact_ui. See also leanprover-community/batteries#1202. -
#8136 adds an initial set of
@[grind]annotations forList/Array/Vector, enough to set up some regression tests usinggrindin proofs aboutList. More annotations to follow. -
#8139 is a follow up to #8055 and implements a
Selectorfor async UDP in order to allow IO multiplexing using UDP sockets. -
#8144 changes the predicate for
Option.guardto bep : α → Boolinstead ofp : α → Prop. This brings it in line with other comparable functions likeOption.filter. -
#8147 adds
List.findRev?andList.findSomeRev?, for parity with the existing Array API, and simp lemmas converting these into existing operations. -
#8148 generalises
List.eraseDupsto allow for an arbitrary comparison relation. Further, it proveseraseDups_append : (as ++ bs).eraseDups = as.eraseDups ++ (bs.removeAll as).eraseDups. -
#8150 is a follow up to #8055 and implements a Selector for
Std.Channelin order to allow multiplexing using channels. -
#8154 adds unconditional lemmas for
HashMap.getElem?_insertMany_list, alongside the existing ones that have quite strong preconditions. Also for TreeMap (and dependent/extensional variants). -
#8175 adds simp/grind lemmas about
List/Array/Vector.contains. In the presence ofLawfulBEqthese effectively already held, via simplifyingcontainstomem, but now these also fire withoutLawfulBEq. -
#8184 adds the
insertMany_appendlemma for all map variants.
Compiler
-
#6063 updates the version of LLVM and clang used by and shipped with Lean to 19.1.2
-
#7824 fixes an issue where uses of 'noncomputable' definitions can get incorrectly compiled, while also removing the use of 'noncomputable' definitions altogether. Some uses of 'noncomputable' definitions (e.g. Classical.propDecidable) do not get compiled correctly by type erasure. Running the optimizer on the result can lead to them being optimized away, eluding the later IR-level check for uses of noncomputable definitions.
-
#7838 adds support for mpz objects (i.e., big nums) to the
shareCommonfunctions. -
#7854 introduces fundamental API to distribute module data across multiple files in preparation for the module system.
-
#7945 fixes a potential race between
IO.getTaskStateand the task in question finishing, resulting in undefined behavior. -
#7958 ensures that after
mainis finished we still wait on dedicated tasks instead of exiting forcefully. If users wish to violently kill their dedicated tasks at the end of main instead they can runIO.Process.exitat the end ofmaininstead. -
#7990 adopts lcAny in more cases of type erasure in the new code generator.
-
#7996 disables CSE of local function declarations in the base phase of the new compiler. This was introducing sharing between lambdas to bind calls w/
donotation, which caused them to later no longer be inlined. -
#8006 changes the inlining heuristics of the new code generator to match the old one, which ensures that monadic folds get sufficiently inlined for their tail recursion to be exposed to the code generator.
-
#8007 changes eager lambda lifting heuristics in the new compiler to match the old compiler, which ensures that inlining/specializing monadic code does not accidentally create mutual tail recursion that the code generator can't handle.
-
#8008 changes specialization in the new code generator to consider callee params to be ground variables, which improves the specialization of polymorphic functions.
-
#8009 restricts lifting outside of cases expressions on values of a Decidable type, since we can't correctly represent the dependency on the erased proposition in the later stages of the compiler.
-
#8010 fixes caseOn expressions with an implemented_by to work correctly with hash consing, even when the elaborator produces terms that reconstruct the discriminant rather than just reusing a variable.
-
#8015 fixes the IR elim_dead_branches pass to correctly handle join points with no params, which currently get considered unreachable. I was not able to find an easy repro of this with the old compiler, but it occurs when bootstrapping Lean with the new compiler.
-
#8017 makes the IR elim_dead_branches pass correctly handle extern functions by considering them as having a top return value. This fix is required to bootstrap the Init/ directory with the new compiler.
-
#8023 fixes the IR expand_reset_reuse pass to correctly handle duplicate projections from the same base/index. This does not occur (at least easily) with the old compiler, but it occurs when bootstrapping Lean with the new compiler.
-
#8124 correctly handles escaping functions in the LCNF elimDeadBranches pass, by setting all params to top instead of potentially leaving them at their default bottom value.
-
#8125 adds support for the
initattribute to the new compiler. -
#8127 adds support for borrowed params in the new compiler, which requires adding support for .mdata expressions to LCNF type handling.
-
#8132 adds support for lowering
casesOnfor builtin types in the new compiler. -
#8156 fixes a bug where the old compiler's lcnf conversion expr cache was not including all of the relevant information in the key, leading to terms inadvertently being erased. The
rootvariable is used to determine whether lambda arguments to applications should get let bindings or not, which in turn affects later decisions about type erasure (erase_irrelevant assumes that any non-atomic argument is irrelevant). -
#8236 fixes an issue where the combination of
extern_libandprecompileModuleswould lead to "symbol not found" errors.
Pretty Printing
-
#7805 modifies the pretty printing of raw natural number literals; now both
pp.explicitandpp.natLitenable thenat_litprefix. An effect of this is that the hover on such a literal in the Infoview has thenat_litprefix. -
#7812 modifies the pretty printing of pi types. Now
∀will be preferred over→for propositions if the domain is not a proposition. For example,∀ (n : Nat), Truepretty prints as∀ (n : Nat), Truerather than asNat → True. There is also now an optionpp.foralls(default true) that when false disables using∀at all, for pedagogical purposes. also adjusts instance implicit binder pretty printing — nondependent pi types won't show the instance binder name. Closes #1834. -
#7813 fixes an issue where
let n : Nat := sorryin the Infoview pretty prints asn : ℕ := sorry `«Foo:17:17». This was caused by top-level expressions being pretty printed with the same rules as Infoview hovers. Closes #6715. RefactorsLean.Widget.ppExprTagged; now it takes a delaborator, and downstream users should configure their own pretty printer option overrides if necessary if they used theexplicitargument (seeLean.Widget.makePopup.ppExprForPopupfor an example). Breaking change:ppExprTaggeddoes not setpp.proofson the root expression. -
#7840 causes structure instance notation to be tagged with the constructor when
pp.tagAppFnsis true. This will make docgen will have{and}be links to the structure constructor. -
#8022 fixes a bug where pretty printing is done in a context with cleared local instances. These were cleared since the local context is updated during a name sanitization step, but preserving local instances is valid since the modification to the local context only affects user names.
Documentation
-
#7947 adds some docstrings to clarify the functions of
Lean.mkFreshId,Lean.Core.mkFreshUserName,Lean.Elab.Term.mkFreshBinderName, andLean.Meta.mkFreshBinderNameForTactic. -
#8018 adjusts the RArray docstring to the new reality from #8014.
Server
-
#7610 adjusts the
TryThiswidget to also work in widget messages rather than only as a panel widget. It also adds additional documentation explaining why this change was needed. -
#7873 fixes a number of bugs related to the handling of the source search path in the language server, where deleting files could cause several features to stop functioning and both untitled files and files that don't exist on disc could have conflicting module names.
-
#7882 fixes a regression where elaboration of a previous document version is not cancelled on changes to the document.
-
#8242 fixes the 'goals accomplished' diagnostics. They were accidentally broken in #7902.
Lake
-
#7796 moves Lean's shared library path before the workspace's in Lake's augmented environment (e.g.,
lake env). -
#7809 fixes the order of libraries when loading them via
--load-dynlibor--plugininleanand when linking them into a shared library or executable. ADynlibnow tracks its dependencies and they are topologically sorted before being passed to either linking or loading. -
#7822 changes Lake to use normalized absolute paths for its various files and directories.
-
#7860 restores the use of builtins (e.g., initializer, elaborators, and macros) for DSL features and the use of the Lake plugin in the server.
-
#7906 changes Lake build traces to track their mixed inputs. The tracked inputs are saved as part of the
.tracefile, which can significantly assist in debugging trace issues. In addition, this PR tweaks some existing Lake traces. Most significant, module olean traces no longer incorporate their module's source trace. -
#7909 adds Lake support for building modules given their source file path. This is made use of in both the CLI and the sever.
-
#7963 adds helper functions to convert between
Lake.EStateTandEStateM. -
#7967 adds a
bootstrapoption to Lake which is used to identify the core Lean package. This enables Lake to use the current stage's include directory rather than the Lean toolchains when compiling Lean with Lean in core. -
#7987 fixes a bug in #7967 that broke external library linking.
-
#8026 fixes bugs in #7809 and #7909 that were not caught partially because the
badImporttest had been disabled. -
#8048 moves the Lake DSL syntax into a dedicated module with minimal imports.
-
#8152 fixes a regression where non-precompiled module builds would
--load-dynlibpackageextern_libtargets. -
#8183 makes Lake tests much more verbose in output. It also fixes some bugs that had been missed due to disabled tests. Most significantly, the target specifier
@pkg(e.g., inlake build) is now always interpreted as a package. It was previously ambiguously interpreted due to changes in #7909. -
#8190 adds documentation for native library options (e.g.,
dynlibs,plugins,moreLinkObjs,moreLinkLibs) andneedsto the Lake README. It is also includes information about specifying targets on the Lake CLI and in Lean and TOML configuration files.
Other
-
#7785 adds further automation to the release process, taking care of tagging, and creating new
bump/v4.X.0branches automatically, and fixing some bugs. -
#7789 fixes
leanpotentially changing or interpreting arguments after--run. -
#8060 fixes a bug in the Lean kernel. During reduction of
Nat.pow, the kernel did not validate that the WHNF of the first argument is aNatliteral before interpreting it as anmpznumber. adds the missing check.