Lean 4.32.0 (2026-07-13)
For this release, 102 changes landed. In addition to the 35 feature additions, and 20 fixes listed below, there were 7 refactoring changes, 2 documentation improvements, 9 performance improvements, 2 improvements to the test suite, and 27 other changes.
Highlights
Lean 4.32.0 makes the new do elaborator the default, expands do notation with the do← marker for effect forwarding, and brings notable performance improvements including a ~10% reduction in import Mathlib time. Lake's linting framework gains option-based control and module-level linters, and an experimental incremental-compilation mode lands behind CLI flags.
This highlights section was contributed by Juanjo Madrigal.
New do Elaborator is Now the Default
#13305 makes the new do elaborator (introduced as experimental in v4.31.0) the default by flipping backward.do.legacy to false. The legacy elaborator remains available via set_option backward.do.legacy true. #13912 and #13931 add significant new capabilities:
do← — Effect Forwarding
#13931 introduces the do← body marker (ASCII do<- body), which lets ordinary continuation-taking wrappers like withReader or Meta.withLocalDecl participate in the surrounding do block's control flow. When do← body appears as the last argument of an application inside a do block, the body's return, break, continue, and mut-variable reassignments are forwarded out through the wrapper to the enclosing block. For instance, let
def withLogging [Monad m] [MonadLiftT IO m] (act : m α) : m α := do
IO.print "log!"
act
Internal do← body can mutate external variables:
def mutForward : IO Nat := do
let mut x := 0
withLogging (do← x := x + 1)
return x
/--
info: log!
---
info: 1
-/
#guard_msgs in
#eval mutForward
It can also trigger an early return:
def retForward : IO Nat := do
let x <- withLogging (do← return 5)
IO.println "unreachable"
return x + 100
/--
info: log!
---
info: 5
-/
#guard_msgs in
#eval retForward
Or break an external loop (and the do← body can be executed multiple times):
def brkForward : IO Nat := do
let mut total := 0
for i in [1, 2, 3, 4, 5] do
total := total + (← withLogging (do←
if i > 3 then break
pure i))
return total
/--
info: log!log!log!log!
---
info: 6
-/
#guard_msgs in
#eval brkForward
The syntax is reminiscent of a nested action (← body), but unlike a nested action, body is not run eagerly before the wrapping function is called. The wrapping function decides when to run body, and code is inserted to forward body's effects to the outer do block.
Arbitrary doElems in Nested Actions
#13912 extends the nestedAction parser (← inside do blocks) to accept arbitrary doElems after ← instead of just terms.
def bumpAndUse : IO Nat := do
let mut y := 1
let x ← pure (← if y < 3 then
y := y + 1
pure y
else
pure 0)
return x + y -- x = 2 and y = 2
/-- info: 4 -/
#guard_msgs in
#eval bumpAndUse
return e inside (← do …) or (← try … catch …) now early-returns from the enclosing do block, not from the nested action. This a breaking change: replace with pure e when value-return from the nested block is intended, or wrap the do block in parentheses ((← (do …))).
Other do Elaborator Improvements
Performance
A fix to DiscrTree insertion (#13928) reduces the time to import Mathlib by approximately 10% by eliminating a non-linearity in the insertion algorithm.
Other notable performance work:
-
#13123 makes the task thread pool reclaim idle worker threads after 5 seconds of inactivity, reducing memory waste from the 1GB default stack size per thread.
-
#13938 adds tail-recursive
@[csimp]runtime replacements for bounded-quantifierDecidableinstances (Nat.decidableBallLT,Nat.decidableExistsLT,Nat.decidableExistsLT'), so running examples like#eval decide (∀ k, k < 2000000 → 0 ≤ k) #eval decide (∃ k, k < 50000000 ∧ k + 1 = 0)no longer take quadratic time or overflow the stack.
-
#13991 adds constant folding for
USizeoperations and common bitwise operations, and #13974 extends it toUSizerelations. #14044 adds constant folding forNat.reprFast.
Monadic Verification: mvcgen' and grind Improvements
The mvcgen' and grind ecosystem continues to mature:
-
#13983 adds
mvcgen' until $t, where$tis a conv-style pattern; verification-condition generation stops as soon as the program matches the pattern. For instance, compare the traces in these two examples:def inc (n : Nat) : Id Nat := do let a ← increaseBy n 1 let b ← increaseBy a 2 let c ← increaseBy b 3 let d ← increaseBy c 4 increaseBy d 5 example (n : Nat) : ⦃⌜True⌝⦄ inc n ⦃⇓ r => ⌜r = n + 15⌝⦄ := n:Nat⊢ ⦃⌜True⌝⦄ inc n ⦃PostCond.noThrow fun r => ⌜r = n + 15⌝⦄ n:Nata✝⁹:Nata✝⁸:a✝⁹ = n + 1a✝⁷:Nata✝⁶:a✝⁷ = a✝⁹ + 2a✝⁵:Nata✝⁴:a✝⁵ = a✝⁷ + 3a✝³:Nata✝²:a✝³ = a✝⁵ + 4a✝¹:Nata✝:a✝¹ = a✝³ + 5⊢ a✝¹ = n + 15 n:Nata✝⁹:Nata✝⁸:a✝⁹ = n + 1a✝⁷:Nata✝⁶:a✝⁷ = a✝⁹ + 2a✝⁵:Nata✝⁴:a✝⁵ = a✝⁷ + 3a✝³:Nata✝²:a✝³ = a✝⁵ + 4a✝¹:Nata✝:a✝¹ = a✝³ + 5⊢ a✝¹ = n + 15 All goals completed! 🐙 example (n : Nat) : ⦃⌜True⌝⦄ inc n ⦃⇓ r => ⌜r = n + 15⌝⦄ := n:Nat⊢ ⦃⌜True⌝⦄ inc n ⦃PostCond.noThrow fun r => ⌜r = n + 15⌝⦄ n:Nata✝⁴:Nata✝³:a✝⁴ = n + 1a✝²:Nata✝¹:a✝² = a✝⁴ + 2a✝:Nat⊢ ⌜a✝ = a✝² + 3⌝ ⊢ₛ wp⟦increaseBy a✝ 4⟧ (fun a => wp⟦increaseBy a 5⟧ (fun r => ⌜r = n + 15⌝, ExceptConds.false), (fun r => ⌜r = n + 15⌝, ExceptConds.false).snd) case vc1 a n:Nata✝³:Nata✝²:a✝⁴ = n + 1a✝¹:Nata✝:a✝² = a✝⁴ + 2a:Nat⊢ ⌜a✝ = a✝² + 3⌝ ⊢ₛ wp⟦increaseBy a✝ 4⟧ (fun a => wp⟦increaseBy a 5⟧ (fun r => ⌜r = n + 15⌝, ExceptConds.false), (fun r => ⌜r = n + 15⌝, ExceptConds.false).snd) n:Nata✝³:Nata✝²:a✝⁴ = n + 1a✝¹:Nata✝:a✝² = a✝⁴ + 2a:Nat⊢ ⌜a✝ = a✝² + 3⌝ ⊢ₛ wp⟦increaseBy a✝ 4⟧ (fun a => wp⟦increaseBy a 5⟧ (fun r => ⌜r = n + 15⌝, ExceptConds.false), (fun r => ⌜r = n + 15⌝, ExceptConds.false).snd) n:Nata✝⁸:Nata✝⁷:a✝⁴ = n + 1a✝⁶:Nata✝⁵:a✝² = a✝⁴ + 2a:Nata✝⁴:a = a✝⁶ + 3a✝³:Nata✝²:a✝³ = a + 4a✝¹:Nata✝:a✝¹ = a✝³ + 5⊢ a✝¹ = n + 15 -- resume: run the remaining program to completion All goals completed! 🐙 -
#13925 consolidates
mvcgen'syntax across tactic andgrind(sym =>) modes:example (n : Nat) : ⦃⌜True⌝⦄ inc n ⦃⇓ r => ⌜r = n + 15⌝⦄ := n:Nat⊢ ⦃⌜True⌝⦄ inc n ⦃PostCond.noThrow fun r => ⌜r = n + 15⌝⦄ sym => n:Nata✝⁹:Nata✝⁸:a✝⁹ = n + 1a✝⁷:Nata✝⁶:a✝⁷ = a✝⁹ + 2a✝⁵:Nata✝⁴:a✝⁵ = a✝⁷ + 3a✝³:Nata✝²:a✝³ = a✝⁵ + 4a✝¹:Nata✝:a✝¹ = a✝³ + 5⊢ a✝¹ = n + 15 n:Nata✝⁹:Nata✝⁸:a✝⁹ = n + 1a✝⁷:Nata✝⁶:a✝⁷ = a✝⁹ + 2a✝⁵:Nata✝⁴:a✝⁵ = a✝⁷ + 3a✝³:Nata✝²:a✝³ = a✝⁵ + 4a✝¹:Nata✝:a✝¹ = a✝³ + 5⊢ a✝¹ = n + 15 (n:Nata✝⁹:Nata✝⁸:a✝⁹ = n + 1a✝⁷:Nata✝⁶:a✝⁷ = a✝⁹ + 2a✝⁵:Nata✝⁴:a✝⁵ = a✝⁷ + 3a✝³:Nata✝²:a✝³ = a✝⁵ + 4a✝¹:Nata✝:a✝¹ = a✝³ + 5⊢ a✝¹ = n + 15; All goals completed! 🐙)mvcgen' invariants?(suggest mode) also works inside sym => … blocks. -
#13881 lets
mvcgen'decompose programs whose head is a typeclass method projection (e.g.Add.add inst a b). -
#13888 teaches
mvcgen'to registerTriple-shaped local hypotheses as specs during VC generation. -
#13971 makes the
cbvtactic available insidegrind's interactivesym =>mode.
Lake: Linter Overhaul and Cache Improvements
Environment Linters via Options
#13893 (building on #13852's builtin linter sets) makes environment linters controlled by Lean options (Lean.Option), just like ordinary linters. Each environment linter is tied to a boolean option, so you can enable or disable it per declaration with set_option linter.X false in ... and across a lint run with the new lake lint --linters=linter.X,-linter.Y flag. Using --lint-only with the same syntax collects information only from the specified linters. Breaking change: the previous lake lint flags --extra, --lint-all, and the builtin_nolint attribute are removed in favour of this option-based control. linter.extra becomes a linter set whose members are the existing extra linters.
Module Linters
#13917 adds module linters, which run once at the end of elaborating a module rather than after every command. A module linter receives the full array of top-level command syntaxes for the module, making it suitable for checks that need a whole-module view (e.g. enforcing module-wide syntactic conventions).
Other Lake Improvements
-
#13961 adds a
--record-exceptionsflag tolake lint, which insertsset_optionflags to silence warnings on the definitions that triggered them. -
#14060 deduplicates cached artifacts by hash, and #14036 refines when and how Lake overwrites cache data with new
--no-overwriteand--force-overwriteoptions. #13949 adds aLAKE_RESTORE_ARTIFACTSenvironment variable to override the workspace'srestoreAllArtifactsconfiguration.
Experimental: Incremental Compilation Caching
#13965 adds experimental CLI flags that cache lean's post-import elaboration state across invocations: --incr-save FILE writes a full snapshot at end of run, --incr-load FILE reuses one at startup, and --incr-header-save FILE writes a header-only snapshot (post-import Environment, no command bodies). A loaded snapshot is reused as far as unchanged syntax allows.
Library Highlights
-
#3727 adds
BitVec.flattenListfor concatenating lists of bitvectors, with characterizing lemmas and a@[csimp]-driven divide-and-conquer implementation that's ~900× faster than a naive left fold. -
#12030 links OpenSSL into Lean's runtime, with #13988 making it lazily loadable.
-
#14054 upstreams
Nat.sqrtfrom Batteries, with characterizing lemmas that avoid exposing internals. -
#13798 simplifies the
Std.TimeAPI:DateTime (tz : TimeZone)is removed and the formerZonedDateTimeis renamed toDateTime. Breaking change: code usingDateTimeorZonedDateTimedirectly will need updating. -
#13908 deprecates
Lean.RBMapandLean.RBTreein favour ofStd.TreeMapandStd.TreeSet. Importers now receive a deprecation warning viaLean.Parser.Command.deprecated_module : command`deprecated_module` marks the current module as deprecated. When another module imports a deprecated module, a warning is emitted during elaboration. ``` deprecated_module "use NewModule instead" (since := "2026-03-19") ``` The warning message is optional but recommended. The warning can be disabled with `set_option linter.deprecated.module false` or `-Dlinter.deprecated.module=false`.deprecated_module. -
#13891 adds opt-in support for serializing closures to
.oleanfiles viaCompactedRegion.save (allowClosures := true).
Breaking Changes
In addition to the do elaborator and linter changes described above:
-
#13305 (new
doelaborator default):donotation now requires aPureinstance, not justBind. The arms ofdo matchare non-dependent by default — writedo match (dependent := true)to recover the legacy term-match expansion.try/catchno longer accepts a body whose result type matches the surrounding expected type only via coercion. Unreachable code now triggers a warning instead of an error. The syntaxlet pat := rhs | otherwisenow scopes over thedoSeqthat follows. -
#13912 (nested actions):
return einside(← do …)or(← try … catch …)now early-returns from the enclosingdoblock. Migration: replace withpure ewhen value-return from the nested block is intended, or wrap in parentheses(← (do …)). -
#13893 (Lake lint): the
--extra,--lint-allflags and@[builtin_nolint]attribute are removed. Uselake lint --linters=linter.X,-linter.Yandset_option linter.X false in ...instead. -
#13798 (Std.Time):
DateTime (tz : TimeZone)is removed; useDateTime(the formerZonedDateTime). Migration: replace uses ofDateTimewith an explicit timezone argument with the newDateTime, and rename references to the oldZonedDateTimetoDateTime. -
#13908:
Lean.RBMapandLean.RBTreeare deprecated. Migration: switch toStd.TreeMapandStd.TreeSet.
Language
-
#14039 fixes a bug where the builting docstring roles for asserting equalities did not properly highlight their contents for downstream consumers of rich docstring info, and exposes a structure that was mistakenly made private.
-
#14030 removes the hypothesis rewriting functionality of
cbv(introduced usingcbv atsyntax) in theSymmode. Additionally, this PR fixes the transparency level when dealing with projections incbv. -
#14025 adds
Lean.DoElemandLean.DoSeqas abbreviations forTSyntax `doElemandTSyntax `Lean.Parser.Term.doSeq, mirroringLean.Term, and uses them throughout thedoelaborator. -
#13961 adds a a
--record-exceptionsflag tolake lint, such that the definitions triggering builtin linting framework warnings will be silenced, by putting an appropriateset_optionflag. -
#13072 moves the status emoji from the stored trace header to the rendering layer.
withTraceNode/withTraceNodeBeforeno longer prependTraceResult.toEmojito the headerMessageData; instead,formatAuxandInteractiveDiagnosticprepend it when rendering.TraceResult.toEmojiis moved fromLean.Util.TracetoLean.Message(next to theTraceResultdefinition) so that both rendering paths can use it. -
#13868 adds
Lean.Environment.hasExposedBody— a small helper that asks "doesenvexport a body fornto downstream modules?". The idiom -
#13981 fixes a private inductive type not being usable as a namespace immediately after its definition.
-
#13970 makes the printed name of a variable in a
do-elaborator error message carry hover info so the infoview surfaces its type. The bulk of the change is a small refactor that introduces aMutVarstructure (declaration identifier + initialFVarId) and threads it through the do-elaborator helpers. -
#13954 prepares the
@[spec]attribute used bymvcgento support both specifications theorems for both new and oldmvcgen'meta theories. -
#13912 extends the
nestedActionparser (←insidedoblocks) to accept arbitrarydoElems after←instead of just terms. The newdoelaborator handles anydoElem; the legacy elaborator (set_option backward.do.legacy true) keeps the old restriction to terms and rejects more generaldoElems with an explicit error. -
#13931 introduces the
do← bodymarker (ASCIIdo<- body), which lets ordinary continuation-taking wrappers likewithReaderorMeta.withLocalDeclparticipate in the surroundingdoblock's control flow. Whendo← bodyappears as the last argument of an application inside adoblock, the body'sreturn,break,continue, andmut-variable reassignments are forwarded out through the wrapper to the enclosing block. -
#13852 adds builtin linter sets — linter sets registered from core Lean code during initialization, complementing the user-facing
register_linter_setcommand — and makeslinter.extraone of them. Enablinglinter.extra(e.g. viaset_option linter.extra trueorlake lint --extra) now activates the extra linters through the same set-membership mechanism as any other linter set. -
#13917 adds module linters, which run once at the end of elaborating a module rather than after every command. A module linter receives the full array of top-level command syntaxes for the module, making it suitable for checks that need a whole-module view (e.g. enforcing module-wide syntactic conventions) rather than per-command checks.
-
#13928 fixes a non-linearity in DiscrTree insertion, reducing the time it takes to
import Mathlibby ~10% -
#13916 fixes the silencing of
deprecatedwarnings inside of definitions that are themselves deprecated and usegrindwith adeprecatedtheorem. -
#13911 removes the
Lean.Parser.Term.liftMethodalias forLean.Parser.Term.nestedActionthat was kept for bootstrapping during the rename in #13910. Now that stage0 has been updated, the alias is no longer needed. -
#13910 renames the
liftMethodparser (the← <action>syntax insidedoblocks) and all of its associated helpers to use the more descriptive "nested action" terminology that the documentation already adopted. -
#13305 makes the new
doelaborator (#12459) the default by flippingbackward.do.legacytofalse. Legacy behavior remains available viaset_option backward.do.legacy true.
Library
-
#14054 upstreams
Nat.sqrtfrom Batteries and just enough theory from mathlib to characterize the function without having to expose its internals. -
#14051 cleans up the internal
Std.Internal.Doweakest-precondition library: the wp application lemmas and theTripleentailment field are renamed to follow the naming convention, the loop-invariant types are curried, and the monad spec lemmas reuse theTriplerules. -
#14048 adds a few lemmas about the way that
cpopandsetWidthinteract onBitVec. -
#3727 adds
BitVec.flattenList, which concatenates a list of bitvectors of a common width into a single bitvector, together with lemmas describing its bits:getLsbD_flattenListandgetMsbD_flattenListcompute an individual bit in terms of the corresponding element of the list, andextractLsb_flattenListdescribes extracting a contiguous range that falls within a single element. For efficient execution,flattenListis replaced at runtime via@[csimp]with a divide-and-conquer implementation costingO(n * L * log L)rather than theO(n * L²)of a naive left fold (≈900x faster at a million elements), while keepingO(log L)recursion depth so it remains stack-safe. -
#13458 adds
Nat.or_two_pow_eq_add_of_lt, a small missing bitwise lemma. -
#13459 adds some missing
ArrayandVectorset!convenience lemmas. -
#13865 adds lemmas to simplify sequencing with
pureinLawfulApplicative. -
#13988 removes
OPENSSL_init_sslfrominitialize_opensslso it helps with loading OpenSSL lazily. -
#13798 simplifies the
Std.TimeAPI by removing theDateTime (tz : TimeZone)and replacing it withZonedDateTimethat got renamed toDateTime. -
#12030 links OpenSSL
-
#13960 renames the
WPAdequatetypeclass toWPSoundto reflect that it encodes the directional soundness arrowwp x P → Internal.Ensures P x(not a bidirectional adequacy correspondence), and replaces theId-only*.of_wp_run_eqfamily with a uniform per-transformer soundness framework that works over any base monad withWPSound. -
#13908 deprecates the
Lean.RBMapandLean.RBTreecontainers in favour ofStd.TreeMapandStd.TreeSet, which offer a more complete and consistent API. Nothing in the Lean repository uses these types any longer, and downstream code should migrate to theStdcontainers. -
#13942 introduces
PersistentHashMap.alterin the same spirit asStd.HashMap.alter. -
#13938 adds tail-recursive
@[csimp]runtime replacements for the bounded-quantifierDecidableinstancesNat.decidableBallLT,Nat.decidableExistsLT, andNat.decidableExistsLT', so that running them no longer takes quadratic time or overflows the stack for largen. -
#13891 adds opt-in support for serializing closures (functions with captured values) to
.oleanfiles viaCompactedRegion.save (allowClosures := true), so a saved function can be loaded back and called, including from a separate process. Regular module data is unaffected and continues to reject closures.
Tactics
-
#14031 implements
SymMsimprocs for reducing bit-vector conversion operations. -
#14029 fixes a
Sym.dsimpbug that could produce an ill-typed term, causing the kernel to reject the resulting goal with errors such asapplication type mismatchorfunction expected. It triggered when alet/λ/∀binder's type or value referenced an earlier binder in the same telescope. -
#14022 fixes
grind?for goals containing hypotheses with inaccessible names. Distinct terms that differ only in inaccessible variables have identical anchors, so anchor references in generated tactic scripts could resolve to the wrong term during replay, producing emptygrind onlysuggestions and scripts that could not close the goal. Thecasestactic now supports anchor ordinal references (e.g.,cases #a56e/2selects the second candidate matching the anchor), andgrind?uses them to disambiguate colliding anchors. -
#14021 fixes an
unknown metavariableerror ingrindthat occurred when instantiatingmatch-congruence equations whose generalized-pattern equalities mention theorem parameters that cannot be determined by E-matching. -
#14020 fixes two bugs that made
grindconstruct proofs that are rejected by the kernel for goals involvingmatch-expressions with overlapping patterns and proof discriminants (#13773). -
#13971 makes the
cbvtactic available insidegrind's interactivesym =>mode. It reduces the goal target using call-by-value evaluation and supports the standardatlocation syntax (cbv at h,cbv at h ⊢,cbv at *) to reduce selected hypotheses, automatically closing equation goals viareflwhen reduction finishes the proof. -
#13983 adds
mvcgen' until $t, where$tis a conv-style pattern (holes_allowed); verification-condition generation stops as soon as the program matches the pattern, leaving it as a VC instead of applying a spec, similar to the existingstepLimitoption. -
#13925 consolidates
mvcgen''s syntax across tactic and grind (sym =>) modes. The grind-modewithclause is removed (use<;>instead), and the tactic-levelwithnow takes a single grind step that shares an E-graph withmvcgen'.mvcgen' invariants?(suggest mode) also works insidesym => …blocks. -
#13944 changes a
filterMapto amapinCNF.convertLRAT'so that tautological clauses becomenonein the array rather then being deleted. -
#13932 implements the
evalGrounddsimprocforSym.dsimp. -
#13621 fixes a bug in the
rcases-family tactics where the InfoView could give "unknown free variable" errors when the cursor was inside the pattern. It hoists applying the fvar substitution to giveaddTermInfo'andaddLocalVarInfothe correct expression. Previously, the substitution only happened inrfl/typed/tuple/alternative branches, which caused stale free variables to be recorded in the info tree. Repeated applications in recursive cases like.parenshould be fine, because the domain offsshould be old fvars and replacement exprs should only refer current-goal fvars, not old-domain fvars. Proof elaboration shouldn't be affected by this PR. -
#13909 makes the
intersperselibrary suggestion combinator honorratioat the endpoints, soratio = 0draws entirely fromselector₂andratio = 1entirely fromselector₁while both selectors still have results. Previously each element was chosen by comparing the achieved fraction ofselector₁contributions againstratiowith a strict<(seeded to0when empty), which leftratio = 1drawing one stray element fromselector₂before settling. The combinator now picks whichever candidate next state keeps the running fraction closest toratio, with ties going toselector₁. -
#13907 makes the
intersperselibrary suggestion combinator requestmaxSuggestionsresults from each of its two selectors instead of splitting the budget byratio, so that if one selector returns fewer suggestions than its allocation the other can compensate to still fill the request. The interspersing ratio and the finalmaxSuggestionscap on the combined result are unchanged. -
#13896 improves the support for universe constraints in the
SymMpattern matcher/unifier. Two new cases are supported -
#13887 factors the whnf-based projection step used inside
mvcgen''s head reducer into a newreduceProjAndUnfold?helper thatunfoldReducibles the projected field only when whnf reduced the structure. The outerSym.unfoldReduciblecall intryHeadReduceProgis no longer needed, so the per-step cost of normalizing abbrevs is proportional to the small unfolded instance body rather than the whole program expression. -
#13888 teaches
mvcgen'to register Triple-shaped local hypotheses as specs as they come into scope during VC generation. This is an existing feature ofmvcgen. -
#13883 teaches
mvcgen'to register Triple-shaped local hypotheses as specs as they come into scope during VC generation. This is an existing feature ofmvcgen. -
#13881 lets
mvcgen'decompose programs whose head is a typeclass method projection (e.g.Add.add inst a b) by reducing through the kernel projection to the instance body. -
#13880 reverts #13870 due to large performance regressions visible on radar that were not caught by benchmarking before merge.
-
#13878 fixes a bug when reducing
match-expressions in theSym.dsimptactic. -
#13870 lets
mvcgen'decompose programs whose head is a typeclass method projection (e.g.Add.add inst a b) by reducing through the kernel projection to the instance body.
Compiler
-
#14044 introduces constant folding for
Nat.reprFast. -
#13123 makes the task thread pool reclaim idle worker threads after 5 seconds of inactivity. Previously, pool threads were allocated on demand but never freed, which could waste significant memory given the new default 1GB stack size per thread.
-
#13991 adds constant folding for
USizeoperations that are already supported in other datatypes. It does so by checking whether the result of applying the operation is equivalent in bothUInt32andUInt64. Furthermore, it also adds constant folding operations for the most common bitwise operations. -
#13989 fixes a bug in the constant folding for
Boolwherein the compiler incorrectly determined 0-ary functions that participate in constant folding to be equal tofalse. -
#13974 adds constant folding for
USizerelation by evaluating them both in theUInt32andUInt64world and applying the fold if both worlds agree. -
#13926 makes
dbgTraceIfSharedprint the shared message in all non-linear situations. Previously it would only trigger ifRC > 1. However,RC = 0andRC < 0are also non-linearity triggers. -
#13924 fixes a code generator panic that occurred when a recursive definition (well-founded or structural) was marked by a
noncomputable sectionand then referenced from computable code. The compiler now reports a clean error, or accepts the second definition when everything occurs in anoncomputable section.
FFI
-
#13952 declares the
extern "C"parameter oflean_mk_bool_data_valueasuint8to match its@[export]ed Lean definition (where aBoolargument lowers touint8_tat the C ABI), fixing awasm32-emscripten/LTO ABI mismatch that trapped during module initialization.
Lake
-
#14060 has Lake deduplicate artifacts by their hash when uploading or downloading to the cache (e.g., in
lake cache putorlake cache get). This fixes possible errors whencurlwas asked to transfer to the same file and/or URL multiple times. -
#14036 refines when and how Lake decides to overwrite data while caching, and has Lake prefer outputs in a local trace file over those stored in the cache.
-
#13893 makes environment linters (the declaration-level checks run by
lake lint --builtin-lint) controlled byLean.Options, just like ordinary linters. Each environment linter is tied to a boolean option, so you enable or disable it per declaration withset_option linter.X false in ...and across a lint run with the newlake lint --linters=linter.X,-linter.Yflag. Using--lint-onlywith the same syntax will only collect information from the specified linters and will not run the default on linters. The previouslake lintflags--extra,--lint-all, and thebuiltin_nolintattribute, are removed in favour of this option-based control. -
#13949 adds a
LAKE_RESTORE_ARTIFACTSenvironment variable that overrides the workspace's defaultrestoreAllArtifactsconfiguration, mirroring howLAKE_ARTIFACT_CACHEoverridesenableArtifactCache. -
#13936 fixes an issue where
depPkgswas not properly set for a transitive dependency that was overriden by a package at a higher level in the dependency graph.
Other
-
#14028 fixes an issue where existence of potential stray files could influence whether a module is loaded under the module system, resulting in unexpected behavior
-
#14019 fixes
mkSimpleThunkTypeto use_instead ofName.anonymousas its binder name. A local declaration whose user name isName.anonymousmatches every identifier inresolveLocalName, shadowing all global constants and making the pretty printer render every constant in the local context as inaccessible (e.g.,True✝). Thematchcompiler usesmkSimpleThunkTypeto create the minor premises of parameterless alternatives, and tactics that introduce these binders using their binder name verbatim (e.g.,grind) ended up with a corrupted local context. Found while investigating #13773. -
#13965 adds experimental CLI flags that cache
lean's elaboration state used for in-process incrementality across invocations:-
--incr-save FILEwrites a full snapshot including the states after import and after each command at the end of the run -
--incr-load FILEreuses such a snapshot at startup, up to the first point of syntactic difference just like incrementality in the language server-
--incr-header-save FILEwrites a cheaper and smaller import-only snapshot
-
-