These release notes describe a release candidate, not the final release. They may be incomplete and are subject to change.
Lean 4.31.0-rc1 (2026-05-28)
For this release, 303 changes landed. In addition to the 104 feature additions, and 101 fixes listed below, there were 17 refactoring changes, 5 documentation improvements, 13 performance improvements, 15 improvements to the test suite, and 48 other changes.
Language
-
#13803 renames the
defLemmalinter todefPropand clarifies its warning message. -
#13862 updates the error message improvement from #10488 to also check for identifier escape characters when providing the improved message. Before, it checked only for identifier start characters.
-
#13853 makes
lake lint --builtin-lintgroup saved text linter diagnostics by the module that produced them, rather than printing one combined block under the top-level module being linted. Each contributing submodule now gets its own-- Text linter diagnostics in <module>:header, mirroring how the environment-linter side already groups results. -
#13844 makes
Lean.Linter.logLintattach an internal tag to every linter warning so thatLean.Linter.recordLintscan reliably distinguish linter-produced messages from other tagged messages (named errors, unknown-identifier messages,hasSorrymarkers, etc.). Previously,recordLintscaptured every message whose top-level kind was non-anonymous, which over-recorded non-linter diagnostics into the persistent lint log. -
#13752 makes projection notation errors always mention a private declaration on a parent structure as the cause when applicable. Previously, for projections that resolved through structure inheritance, the hint was silently omitted, leaving users without the actual cause.
-
#13813 fixes an issue where
beforeElaborationattributes were not being run oninductive/structure/coinductivecommands. Closes #13433. -
#13811 updates the
#wherecommand to be able to reportmodule-related scope state, for example a@[expose] public meta sectionline in the output. -
#13760 improves elaboration performance for structure instance notation with large numbers of fields. It also uses beta-reducing substitution for structure parameters, which is already the case for structure fields.
-
#13807 modifies the app elaborator to beta reduce arguments while substituting them into expected types for later arguments. This makes it consistent with
inferTypeandinstantiateMVars, which both beta reduce substitutions. In particular, this change ensures that the app elaborator behaves as if it creates metavariables for each parameter and assigns elaborated arguments to the metavariables. Breaking change: tactic proofs may need to be modified to remove unnecessary steps, e.g.dsimp onlysteps that were previously for beta reductions. -
#13808 enforces that Verso docstring extensions should always be meta at attribute application time, giving better error messages, and ensures that the generated argument parser helper is also meta and has the same visibility.
-
#13801 adds two new fields to
DoOps,splitMonadApp?andmkMonadApp, so that callers ofelabDoWithcan use indexed monads likeMeasure α(whereMeasure : (α : Type u) → [MeasureSpace α] → Type ucarries instance arguments) that the defaultm αdecomposition cannot handle. The existing behavior moves intoDoOps.default. -
#13800 renames the
doelaborator'smkMonadicTypetomkMonadApp, aligning it with the existingmkPureApp/mkBindAppnaming convention inDoOps. -
#13780 is part 2 to #13779. It completes the transition of the configuration evaluation metaprograms into being builtin elaborators.
-
#13779 makes the command elaborators for configuration evaluation metaprogramming be builtins, to avoid bootstrapping ABI issues in core Lean due to the interpreter evaluating large parts of the elaborator before all builtin initializers are run. (This is part 1; #13780 will be applied after a stage0 update.)
-
#13762 does some refactoring of the function application elaborator, and it improves
trace.Elab.apptracing. It also improves asymptotic complexity by more carefully substituting arguments into the function's type and by changing how named argument dependency suppression is implemented. For dot notation, it now constructs base projections directly rather than using the app elaborator. It fixes a bug in the eta args feature where more explicit arguments would be turned into implicit arguments than expected, and it improves expected type propagation by following the rules from the main app elaborator. -
#13772 closes https://github.com/leanprover/lean4/issues/13770 by including
Config.zetaUnusedinConfig.toKey. Without this, two configs that differ only inzetaUnusedshare aWHNF/isDefEqcache key, so reductions performed under one setting can be returned for the other. The new bit sits at position 22, immediately abovezetaHave. -
#13768 fixes a long-standing bug in
Meta.Config.toKeyandContext.setTransparencywhereTransparencyModewas packed into only 2 bits of the cache key, even though it has 5 constructors (.all,.default,.reducible,.instances,.none). The.nonecase (value4, i.e.0b100) overlapped with thefoApproxbit, so configurations differing only in transparency vs.foApproxcould collide in theisDefEq/WHNFcache, andContext.setTransparencycorrupted the neighbouring bit when switching to/from.none. -
#13763 adds
MessageData.withExprHover, for creating messages that show information about an expression when hovered over. AwithExprHoverMvariant captures the current local context. -
#13758 improves
Expr.instantiateBetaRevRangeto be more efficient in the common case where lambda functions are not being instantiated, and it increases expression sharing in applications. -
#13737 changes the separator between the plugin file name and the initialization function in
--pluginfrom:to=. This prevents clashes with the:in drive prefixes on Windows. -
#13651 replaces the previous tactic configuration system with a significantly more efficient one that supports custom configuration syntaxes and processing. On a simple benchmark, configuration evaluation takes 6.2% of the time it used to. The
declare_config_elabcommand generates a configuration elaborator that now directly constructs configuration objects; previously it relied onMeta.evalExpr', which involved running a configuration through the full term elaboration, compilation, and evaluation processes. The generated configuration elaborators now also have the capability to do directSyntaxevaluation in common cases, skipping term elaboration. Furthermore, the elaborator accepts configurations more liberally: any user-defined syntax that has the form of anoptConfig-style configuration or configuration item (including, e.g.,namedArguments) is accepted. ImportLean.Elab.ConfigEvalto use the system; see this module for some documentation in addition to the docstrings inLean.Elab.ConfigEval.Commands. Furthermore, thesimptactic now also has(user.optionName := ...)user configuration options, which can be declared using a globaltactic.simp.user.optionNameoption; usegetUserConfigOptionandwithUserConfigto access and set these in metaprograms. -
#13550 improves the logic and performance of the
checkImpossibleInstancefunction to detect more arguments that are impossible to infer for typeclass synthesis. It also improves the formatting of the error messages forcheckImpossibleInstanceandcheckNonClassInstanceto be more readable. -
#13730 fixes a regression introduced in #7166 where, after fixed and varying parameters were allowed to be reordered, three places in
Lean.Elab.Structural.FindRecArgstill indexed the concatenationxs ++ yswithrecArgInfo.recArgPoseven thoughrecArgPosrefers to the original parameter order. With fixed parameters interleaved with the structural argument, this picked the wrong element: error messages named the wrong parameter, andargsInGroup's nested-inductive recognition silently rejected otherwise-valid mutual definitions. -
#13728 improves hovers and completions for compound field names in structure instance notation. Previously a field like
x.fstwould only have information associated toxattached to the entire syntax, but nowxandfstare treated separately. -
#13715 improves the message of
unusedVariableslinter, by replacing potentially confusing "unused variablex" message with "Variable namexis not explicitly referenced. The binding can be removed (if unused) or named_(if used implicitly)." -
#13710 makes the test-only
waitForMessagehelper abort promptly when the Lean language server reports a fatalError, instead of blocking until the outer test framework's timeout kills the process. -
#11313 ensures that
withSetOptionIndoes not modify the infotrees or error on malformed option values, and thus avoids panics in linters that traverse the infotrees withvisitM. -
#13595 silences the
Linter.deprecatedwarnings inside of definitions that are themselves deprecated. -
#13209 adds
whileM, a counterpart toLean.Loop.forInthat admits a one-step unfolding lemmawhileM_eq(impossible to prove for the originalpartial def).Lean.Loop.forInnow expands towhileM, sorepeat/whilekeep working without source changes, and theSpec.whileM/Spec.forIn_loop@[spec]theorems letmvcgendischarge their bodies given a Nat variant and anα ⊕ βinvariant. -
#13670 adds support for blockquotes to Verso docstrings, which had been missing before. It also substantially improves the robustness of Verso->Markdown rendering of docstrings, especially the handling of blockquote line prefixes.
-
#13663 replaces the
check_canceltwo-way coordination protocol used bytests/server_interactive/cancellation_par.leanwith a single tacticblock_until_cancelled "<label>". The first invocation for a label registers a promise, prints<label>: blocked, and loops onCore.checkInterrupteduntil the cancel token fires (thenfinallyresolves the promise). Any later invocation for the same label waits on that promise — so the test only terminates if the first invocation actually exited the loop. If cancellation fails to propagate, the second invocation'sIO.waitblocks forever and the test hangs (timeout = failure), with no false-success path. -
#13548 fixes possible corruption when recovering from memory exhaustion.
-
#13613 makes the elaborator reject
@[foo]when the module that registersfoois not visibly imported into the current file but merely loaded as IR. Previously such uses silently elaborated but led to divergence of cmdline and server behavior and causedlake shake --fixto flip-flop on successive runs (#13599). -
#13510 adds the ability to specify a name for the initialization function of a Lean plugin on load.
-
#13645 fixes the termination checker reporting errors at the wrong recursive call site when a function contains structurally-identical recursive calls at different source locations.
-
#13547 prevents silent allocation failures leading to memory corruption when not using GMP.
-
#13596 fixes private(ly imported) default instances from accidentally being used in public signatures, leading to follow-up errors.
-
#13574 ensures consistent metavariable behavior between Verso docstrings and Verso moduledocs by sharing more code between their elaborators. It also improves the error message when a metavariable leak is prevented.
-
#13528 gives the
specializetactic the ability to instantiate universal quantifiers other than the first usingspecialize h (y := v)syntax. It also fixes an issue whereMVarId.assertAfterdid not record variable alias information, and an issue whereMVarId.replaceandMVarId.replaceLocalDecldid not take metavariables into account when calculating dependencies. Additionally it fixes some uninstantiated metavariables bugs, including one in the Infoview tactic state hypothesis diff. -
#13428 fixes parallel tactic combinators (
attempt_all_par,first_par) leaking their subtasks when the server cancels elaboration on re-elaboration. Subtasks spawned viaCoreM.asTask(and itsMetaM/TermElabM/TacticMvariants) get a freshIO.CancelToken, which previously had no link to the parent token;cancelRecwould set the command-level token but the children kept running. -
#13569 addresses two review points on
IO.CancelToken:-
setnow resolves the underlying promise before writing theBoolfast-path flag, so observingisSet = trueimplies any synchronously chainedonSetcallback has already run. The previous order (flag first, then resolve) was a subtle footgun: code seeingisSet = truecould not rely on the cancellation task having fired. -
The underlying promise and the task it produces are kept private. The prior
task : Task (Option Unit)accessor is removed; consumers should useonSetto react to cancellation. A comment on the structure records that re-exposing the task in the future requires re-auditing the order insetfor races between the promise and theBoolflag.
-
-
#13303 moves
IO.CancelTokenfromInit.System.IOto its own fileInit.System.CancelToken, backed byIO.Promise Unitinstead ofIO.Ref Bool. This enables non-polling cancellation propagation: the token's underlying promise can be used directly withIO.waitAny, and callbacks can be registered to fire when cancellation is requested. -
#13542 replaces the catch-all "unsupported pattern in syntax match" error that the new
doelaborator produces for typical pattern mistakes (#2215, #8304, #10393) with the proper diagnostics from the regular pattern-var collector (e.g. "Invalid pattern: Expected a constructor or constant marked with[match_pattern]", "ambiguous pattern, use fully qualified name"), pointing at the offending pattern. -
#13359 adds a
linter.redundantExposeoption (defaulttrue) that warns when@[expose]or@[no_expose]attributes have no effect:-
@[expose]onabbrev(always exposed) or non-Propinstance(always exposed) -
@[expose]on adefinside an@[expose] section(already exposed by the section) -
@[expose]/@[no_expose]in a non-modulefile (no module system) -
@[no_expose]on a declaration that wouldn't be exposed by default
-
-
#13534 generalizes the
whilesyntax indoblocks so that the condition can be anydoIfCond, the same condition form already accepted byif. As a result,while let pat := e do …andwhile let pat ← e do …are now supported in addition towhile cond do …andwhile h : cond do …. The previously separatedoWhileanddoWhileHparsers and their accompanying macros are unified into a singledoWhileparser whose macro delegates to the existingdoIfdesugaring. -
#13523 allows tactic macros and elaborators to opt out of automatic fallback to previous macros/elabs on failure.
throwUnsupportedSyntaxis unaffected. -
#13363 replaces the transparency bump from
.reducibleto.instancesinwhnfMatcherwith an explicit allowlist incanUnfoldAtMatcher. Previously,whnfMatcherwould unfold allimplicitReducibledefinitions and allfromClassprojections when reducing match discriminants. This made it impossible to mark definitions asimplicit_reduciblewithout silently affecting match reduction behavior. -
#13512 changes
whnfAuxin the equation-theorem generation machinery to use reducible transparency (whnfR) instead of instances transparency (whnfI). Previously, the loop inEqns.gowould unfold instances on the LHS, which interacts badly with users that markdite/iteasimplicit_reducible: equation generation would reduce past thediteand get stuck instead of committing to a branch. The original motivation forwhnfI(reducingNat.rec ... (OfNat.ofNat 0)residuals frommatchon numeric literals) is already covered by the surroundingsimpMatch?/simpIf?/simpTargetStarsteps inEqns.go, so the full test suite continues to pass. -
#13506 appends
unreachable!to the expansion ofbreak-lessrepeatwhen the expected result type does not unify withPUnit. The continuation then has a polymorphic value, so the enclosing do block's result type is inferred without a user-written filler, andControlInfofor break-lessrepeatcan reportnoFallthroughhonestly — dead-code warnings on subsequent elements are now actionable. -
#13507 exposes the
Pure.pure/Bind.bindapplications emitted by thedoelaborator as pluggable closures, so external surface syntaxes (e.g. anidonotation for indexed monads) can reuse the fulldomachinery while emitting alternate constants. -
#13491 fixes the
ControlInfoinference for a do-blockmatch: the fold over the match arms started fromControlInfo.pure(defaults tonumRegularExits := 1,noFallthrough := false), butalternativesumsnumRegularExitsand ANDsnoFallthrough, so the fold identity is{ numRegularExits := 0, noFallthrough := true }. With the wrong base, amatchwhose arms allbreak/continue/returnreportednumRegularExits = 1andnoFallthrough = false, suppressing the dead-code warning on the continuation after the match. The fix corrects both the inference handler inInferControlInfo.leanand the fold inelabDoMatchCore. -
#13502 splits
ControlInfo's dead-code signal in two.numRegularExitsis now purely syntactic: how many times the block wires its continuation into the elaborated expression, consumed bywithDuplicableContas a join-point duplication trigger (> 1). The newnoFallthrough : Boolasserts that the next doElem in the enclosing sequence is semantically irrelevant;falseasserts nothing. Invariant:numRegularExits = 0 → noFallthrough; the converse does not hold.sequencederivesnoFallthrough := a.noFallthrough || b.noFallthrough(and aggregates syntactic fields unconditionally);alternativederives it asa.noFallthrough && b.noFallthrough. The dead-code warning gate inwithDuplicableContandControlLifter.ofContnow readsnoFallthrough. -
#13494 stops the
repeatinference handler from reportingnumRegularExits := 0for break-less bodies. For break-lessrepeatthe loop never terminates normally, so0looks more accurate semantically, but the loop expression still has typem Unitand the do block's continuation after the loop is what carries that type. Reporting0makes the elaborator flag that continuation as dead code, yet there is no way for the user to remove it that is also type correct — unless the enclosing do block's monadic result type happens to beUnit. PinningnumRegularExitsat1(matchingfor ... in) eliminates those spurious warnings. -
#13489 fixes a bug where the nesting level in Verso Docstrings is forgotten when there's a doc comment with no headers.
-
#13486 fixes
inferControlInfoSeqandControlInfo.sequenceto keep aggregatingbreaks/continues/returnsEarly/reassignspast elements whoseControlInforeportsnumRegularExits := 0. Previously the analysis short-circuited at such elements, so any trailingreturn/break/continuewas missing from the inferred info. The elaboration framework only skips subsequent doElems syntactically for top-levelreturn/break/continue; for every othernumRegularExits == 0case (e.g. amatch/if/trywhose branches all terminate, or arepeatwithoutbreak) the elaborator keeps visiting the continuation and the for/match elaborator then tripped its invariant check withEarly returning ... but the info said there is no early return. With this change the inferred info matches what the elaborator actually sees, which also removes the need for thenumRegularExits := 1workaround onrepeatintroduced in #13479. -
#13477 fixes a benchmark regression introduced in #13475:
eqnOptionsExtwas using.async .asyncEnvasyncMode, which accumulates state in thecheckedenvironment and can block. Switching to.local— consistent with the neighbouringeqnsExtand the other declaration caches insrc/Lean/Meta— restores performance (thebuild/profile/blocked (unaccounted) wall-clockbench moves from +33% back to baseline)..localis safe here becausesaveEqnAffectingOptionsis only called during top-leveldefelaboration and downstream readers see the imported state; modifications on non-main branches are merged into the main branch on completion. -
#13475 replaces the eager equation realization that was triggered by non-default values of equation-affecting options (like
backward.eqns.nonrecursive) with aMapDeclarationExtensionthat stores non-default option values at definition time. These values are then restored when equations are lazily realized, so the same equations are produced regardless of when generation occurs. -
#13367 removes some cases where
simpwould significantly overrun a timeout. -
#13447 removes the transitional
syntaxdeclarations forrepeat,while, andrepeat ... untilfromInit.Whileand promotes the corresponding@[builtin_doElem_parser]defs inLean.Parser.Dofromlowto default priority, making them the canonical parsers. -
#13442 promotes the
repeat,while, andrepeat ... untilparsers fromsyntaxdeclarations inInit.Whileto@[builtin_doElem_parser]definitions inLean.Parser.Do, alongside the other do-element parsers. Thewhilevariants andrepeat ... untilget@[builtin_macro]expansions;repeatitself gets a@[builtin_doElem_elab]so a follow-up can extend it with an option-driven choice betweenLoop.mkand a well-foundedRepeat.mk. -
#13437 adds a builtin
doElem_control_infohandler fordoRepeat. It is ineffective as long as we have the macro forrepeat. -
#13434 names the
repeatsyntax (doRepeat) and installs dedicated elaborators for it in both the legacy and new do-elaborators. Both currently expand tofor _ in Loop.mk do ..., identical to the existing fallback macro inInit.While. -
#13389 adds two validation checks to
addInstancethat provide early feedback for common mistakes in instance declarations:-
Non-class instance check: errors when an instance target type is not a type class. This catches the common mistake of writing
instancefor a plain structure. Previously handled by thenonClassInstancelinter in Batteries (Batteries.Tactic.Lint.TypeClass), this is now checked directly at declaration time. -
Impossible argument check: errors when an instance has arguments that cannot be inferred by instance synthesis. Specifically, it flags arguments that are not instance-implicit and do not appear in any subsequent instance-implicit argument or in the return type. Previously such instances would be silently accepted but could never be synthesised.
-
-
#13315 fixes
processDefDerivingto propagate themetaattribute to instances derived via delta deriving, so thatderiving BEqinside apublic meta sectionproduces a meta instance. Previously the derivedinstBEqFoowas not marked meta, and the LCNF visibility checker rejected meta definitions that used==on the alias — this came up while bumping verso to v4.30.0-rc1. -
#13404 fixes #12846, where the new do elaborator produced confusing errors when a do element's continuation had a mismatched monadic result type. The errors were misleading both in location (e.g., pointing at the value of
let x ← valuerather than theletkeyword) and in content (e.g., mentioningPUnit.unitwhich the user never wrote). -
#13420 fixes a panic when
coinductivepredicates are defined inside macro scopes where constructor names carry macro scopes. The existing guard only checked the declaration name for macro scopes, missing the case where constructor identifiers are generated inside a macro quotation and thus carry macro scopes. This causedremoveFunctorPostfixInCtorto panic onName.numcomponents from macro scope encoding. -
#13413 adds an internal
skipsyntax for do blocks, intended for use by theifandunlesselaborators to replacepure PUnit.unitin implicit else branches. This gives the elaborator a dedicated syntax node to attach better error messages and location info to, rather than synthesizingpure PUnit.unitwhich leaks internal details into user-facing errors. -
#13391 adds level instantiation and normalization in
getDecLevelandgetDecLevel?before callingdecLevel. -
#13395 makes the
deriving Inhabitedhandler forstructures be able to inheritInhabitedinstances from structure parents, using the same mechanism as for class parents. This fixes a regression introduced by #9815, which lost the ability to applyInhabitedinstances for parents represented as subobject fields. With this PR, now it works for all parents in the hierarchy. -
#13399 fixes #12827, where hovering over
forloop variablesxandhinfor h : x in xs doshowed no type information in the new do elaborator. The fix addsTerm.addLocalVarInfocalls for the loop variable and membership proof binder after they are introduced bywithLocalDeclsDinelabDoFor. -
#13397 improves error reporting when the
doelaborator produces an ill-formed expression that failscheckedAssigninwithDuplicableCont. Previously the failure was silently discarded, making it hard to diagnose bugs in thedoelaborator. Now a descriptive error is thrown showing the join point RHS and the metavariable it failed to assign to. -
#13396 fixes #12768, where the new
doelaborator produced a "declaration has free variables" kernel error when the bind continuation's result type was definitionally but not syntactically independent of the bound variable. The fix moves creation of the result type metavariable beforewithLocalDecl, so the unifier must reduce away the dependency. -
#13325 adds warnings when registering
@[simp]theorems whose left-hand side has a problematic head symbol in the discrimination tree:-
Variable head (
.starkey): The theorem will be tried on everysimpstep, which can be expensive. The warning notes this may be acceptable forlocalorscopedsimp lemmas. Controlled bywarning.simp.varHead(default:true). -
Unrecognized head (
.otherkey, e.g. a lambda expression): The theorem is unlikely to ever be applied bysimp. Controlled bywarning.simp.otherHead(default:true).
-
-
#13390 changes the linear BEq derivation strategy to use
Nat.decEqinstead ofdecEqwhen comparing constructor indices. Since constructor indices are alwaysNat, usingNat.decEqdirectly is more appropriate because it is@[reducible], whereas the genericdecEqis only semireducible and does not unfold at.reducibletransparency. This makes the generated code more transparent-friendly. -
#13356 upstreams environment linters of batteries to core lean.
-
#13360 fixes #13268 where
local macro(and other local declarations) with compound names of depth ≥ 3 would silently lose their local entries. -
#13374 fixes
SizeOfinstance generation for public inductive types that have private constructors. The spec theorem proof construction needs to unfold_sizeOfhelper functions which may not be exposed in the public view, so we usewithoutExportingfor the proof construction and type check. -
#13239 fixes an issue where
(builtin_)initializeinsidemodulewould not allow referencing private defs in its type unless explicitly prefixed withprivate. -
#9815 changes the
Inhabitedderiving handler forstructuretypes to use default field values when present; this ensures that{}anddefaultare interchangeable when all fields have default values. The handler effectively usesby refine' {..} <;> exact defaultto construct the inhabitant. (Note: when default field values cannot be resolved, they are ignored, as usual for ellipsis mode.) -
#13318 adds a check for OS-forbidden names and characters in module names. This implements the functionality of
modulesOSForbiddenlinter of mathlib. -
#13262 extends Lean's syntax to allow explicit universe levels in expressions such as
e.f.{u,v},(f e).g.{u}, ande |>.f.{u,v} x y z. It fixes a bug where universe levels would be attributed to the wrong expression; for examplex.f.{u}would be interpreted asx.{u}.f. It also changes the syntax of top-level declarations to not allow space between the identifier and the universe level list, and it fixes a bug in thecheckWsBeforeparser where it would not detect whitespace acrossoptionalparsers. -
#13332 fixes universe unification for
forloops withmutvariables whose types span multiple implicit universes. The old approach usedensureHasType (mkSort mi.u.succ)per variable, which generated constraints likemax (?u+1) (?v+1) =?= ?u+1that the universe solver cannot decompose. The new approach usesgetDecLevel/isLevelDefEqon the decremented level, producingmax ?u ?v =?= ?uwhichsolveSelfMaxhandles directly. -
#13229 wraps the top-level command parser with
withPositionto enforce indentation inbyblocks, combined with an empty-by fallback for better error messages. -
#13320 changes the auto-generated
sizeOfdefinitions to be not exposed and thesizeOf_spectheorem to be not marked[defeq]. -
#13311 adds an optional
markMeta : Bool := falseparameter toaddAndCompile, so that callers can propagate themetamarking without manually splitting intoaddDecl+markMeta+compileDecl. -
#13319 amends #13317 to suggest
:= (rfl)as the recommended way to avoid a theorem to be automatically marked[defeq], for consistency with existing documentation. Rationale: the special treatment of:= rflis based on syntax, not the proof term, so it’s appropriate to use different syntax. And also I like the way it reads like a “muted whisper ofrfl”. -
#13223 adds a warning preventing a user from applying global attribute using
... in ..., e.g.theorem a : True := trivial attribute [simp] a in def b : True := a
-
#13317 adds an opt-in linter (
set_option simp.rfl.checkTransparency true) that warns when arflsimp theorem's LHS and RHS are not definitionally equal at.instancestransparency. Bad rfl-simp theorems — those that only hold at higher transparency — create problems throughout the system becausesimpanddsimpoperate at restricted transparency. The linter suggests two fixes: useid rflas the proof (to remove therflstatus), or mark relevant constants as[implicit_reducible]. -
#13304 makes the delta-deriving handler create
theoremdeclarations instead ofdefdeclarations when the instance type is aProp. Previously,deriving instance Nonempty for Foowould always create adef, which is inconsistent with the behavior of a handwritteninstancedeclaration. -
#13281 marks any exposed (non-private) auxiliary match declaration as
[implicit_reducible]. This is essential when the outer declaration is marked asinstance_reducible— without it, reduction is blocked at the match auxiliary. We do not inherit the attribute from the parent declaration because match auxiliary declarations are reused across definitions, and the reducibility setting of the parent can change independently. This change prepares for implementing the TODO atExprDefEq.lean:465, which would otherwise cause too many failures requiring manual[implicit_reducible]annotations on match declarations whose names are not necessarily derived from the outer function. -
#13280 adds a new option
backward.isDefEq.respectTransparency.typesthat controls the transparency used when checking whether the type of a metavariable matches the type of the term being assigned to it duringcheckTypesAndAssign. Previously, this check always bumped transparency to.default(viawithInferTypeConfig), which is overly permissive. The new option uses.instancestransparency instead (viawithImplicitConfig), matching the behavior already used for implicit arguments. -
#13266 changes the counter-example accumulator in the match compiler from a
List(built with cons, producing reverse order) to anArray(built with push, preserving declaration order). Missing cases are now reported in the order constructors appear in the inductive type definition. -
#13243 changes elaboration of structure instance notation when used in patterns (e.g.
s matches { x := 1, y := [] }) so that the structure's default values are not used to elaborate the pattern. The motivation is that default values frequently lead to surprisingly over-specific patterns. It will now report "field missing" errors. The error can be suppressed using{ x := 1, .. }ellipsis notation, which has the same behavior as before. The pretty printer is also modified to stay in sync with this feature. Breaking change: patterns using structure instance notation may need missing fields or a..added, as appropriate. -
#13195 adds support for marking options as deprecated. When a deprecated option is used via
set_option, a warning is emitted (controlled bylinter.deprecated.options). -
#13255 adds support for let configuration options (
(eq := h),+nondep,+usedOnly,+zeta) indoblockletandhavedeclarations, matching the behavior available in term-levellet/have. Configuration options are rejected withlet mutsince they are incompatible with mutable bindings.+postponeValueand+generalizeare also rejected indoblocks. -
#13250 extends the
doLet,doLetElse,doLetArrow, anddoHaveparsers to acceptletConfig(e.g.(eq := h),+nondep,+usedOnly,+zeta), matching the syntax of term-levellet/have. The elaborators are adjusted to handle the shifted syntax indices but do not yet process the configuration; that will be done in a follow-up PR after stage0 is updated, allowing the use of proper quotation patterns. -
#13245 extends Lean syntax for dotted function notation (
.f) to add support for explicit mode (@.f), explicit universes (.f.{u,v}), and both simultaneously (@.f.{u,v}). This also includes a fix for a bug involving overloaded functions, where it used to give erroneous deprecation warnings about declarations that the function did not elaborate to. -
#13232 fixes a panic when compiling mutually recursive definitions that use
casesOnon indexed inductive types (e.g.Vect). ThesplitMatchOrCasesOnfunction inWF.UnfoldassertedmatcherInfo.numDiscrs = 1, but for indexed types the casesOn recursor has multiple discriminants (indices + major premise). The fix uses the last discriminant (the major premise) and lets thecasestactic handle index discriminants automatically. -
#13002 adds a
deprecated_modulecommand that marks the current module as deprecated. When another module imports a deprecated module, a warning is emitted during elaboration suggesting replacement imports. -
#13205 fixes
FirstTokens.seq (.optTokens s) .unknownto return.unknown. This occurs e.g. when an optional (with first tokens.optTokens s) is followed by a parser category (with first tokens.unknown). PreviouslyFirstTokens.seqreturned.optTokens s, ignoring the fact that the optional may be empty and then the parser category may have any first token. The correct behavior here is to return.unknown, which indicates that the first token may be anything. -
#13220 adds
checkSystemcalls to several code paths that can run for extended periods without checking for cancellation, heartbeat limits, or stack overflow. This improves responsiveness of the cancellation mechanism in the language server. -
#13108 adds a
deprecated_syntaxcommand that marks syntax kinds as deprecated. When deprecated syntax is elaborated (in terms, tactics, or commands), a linter warning is emitted. The warning is also emitted during quotation precheck when a macro definition uses deprecated syntax in its expansion. -
#13219 moves
hasAssignableMVar,hasAssignableLevelMVar, andisLevelMVarAssignablefromMetavarContext.leanto a newLean.Meta.HasAssignableMVarmodule, changing them from generic[Monad m] [MonadMCtx m]functions toMetaMfunctions. This enables addingcheckSystemcalls in the recursive traversal, which ensures cancellation and heartbeat checks happen during what can be a very expensive computation.
Library
-
#13863 changes the e-matching annotations on
BitVecto avoid automatically going fromgetMsbDtheory togetLsbDtheory. The key reason being that all lemmas are already duplicated betweengetMsbDandgetLsbDanyways. Thus, whenever we connect them all lemmas fire in both variants even though usually one is already sufficient. In order to make this possible without reducing proof strength noticeably we introduce two changes:-
Write or annotate a few additional
BitVec.getMsbDlemmas to match the reasoning power ofBitVec.getLsbD. Most notablygetMsbD_eq_getElemsogetMsbDcan attempt to convert intogetElemon its own. -
Introduce
grind_pattern getMsbD_eq_getLsbD => x.getMsbD i, x.getLsbD _such that whenever we have bothgetMsbDandgetLsbDon the same value in scope we attempt to match them up. We expect that this annotation should usually not fire much as mostget*Dcan probably be converted intogetElemand be worked from there.
-
-
#13850 removes the grind annotation that makes
getElem?_postrigger wheneverc[i]is in the e-graph. We do this to avoid reasoning aboutc[i]?just becausec[i]is available. The trigger for instantiatinggetElem?_poswheneverc[i]?is in scope remains in order to nudge grind towards proving or disproving the bounds check. -
#13689 makes the unfolding lemma for
whileMderivable from aLean.Order.MonadTailinstance. The public entry point iswhileM_eq_of_monadTailinInit.Internal.Order.While; the underlying pinning predicatewhileM.Predand the conditionalwhileM_eqlemma inInit.Whileare kept module-internal. -
#13787 fixes a small docsting error for
String.split. -
#13748 fixes premise selection silently dropping relevant premises when the goal was reached via
induction. -
#13750 refines MePo premise selection so that (1) candidates are restricted to theorems, matching the convention already used by
SineQuaNonandSymbolFrequency, and (2) the result is ordered lexicographically by(iteration, score)rather than by score alone. -
#13747 fixes the MePo premise selector returning its lowest-scoring premises instead of its best ones.
-
#13457 adds the missing
ByteArraypush andset!lemmas that are still carried locally inZipForStd.ByteArraydownstream. -
#13654 adds
Dyadic.divAtPrec a b prec, returning the greatest dyadic with precision at mostprecwhich is less than or equal toa/b(and0whenb = 0). Mirroring the existinginvAtPrec, the characterising lemmasdivAtPrec_mul_leandlt_divAtPrec_add_inc_mulare also provided. -
#13718 fixes tests in context_async.lean by removing all the issues with Async.sleep and IO.sleep and improving how ContextAsync.race works.
-
#13567 adds Locale and LocaleSymbols for configurable date/time formatting. It also modifies alignedWeekOfMonth and weekOfYear so it contains a parameter to the first of the week.
-
#13565 fixes an issue where the missing /etc/localtime caused a failure even when TZ and TZDIR were present.
-
#13675 adds a
WallTimetype representing a point in time as nanoseconds since1970-01-01T00:00:00local time. It also removes thesinceUNIXEpochandAssumingUTCsuffixes becauseTimestampimplies UTC, andWallTimeimplies it is based on the WallTime epoch (defined in the comment as1970-01-01T00:00:00). -
#13693 generalizes a number of
Vectorlemmas about++so that the two appended vectors no longer need to share the same size index:sum_append,prod_append, their_nat/_intvariants,flatMap_append,unattach_append,eraseIdx_append_of_lt_size, anderaseIdx_append_of_length_le. -
#13521 prevents undefined behavior in
readModuleDataParts #[]on configurations withoutLEAN_MMAP. Previously this would lead to out-of-bounds indexing. -
#13549 makes
readModuleDataPartsreport a clearer error if there is insufficient memory to load a module. -
#13627 renames
UInt8.ofNatTruncatetoUInt8.ofNatClamp. -
#13583 changes
Invariant,StringInvariant, andStringSliceInvariantfromabbrevto@[spec_invariant_type, simp, grind =] def, so that they remain visible as applications of a named constant in proof states (whereSymMdoes not unfolddefs) and can be detected as invariant types byisSpecInvariantType. The@[simp, grind =]annotations ensure they still unfold on demand undersimpandgrind. -
#13582 adds several entailment-related lemmas to
Std.Do.SPredandStd.Do.PostCond, intended for goal-decomposition during program verification proof automation. -
#12965 Introduces new foundations for reasoning about monadic Lean code. Eventually we will port
mvcgenon top of these new foundations, to make the framework more general and robust. -
#13546 prevents memory exhaustion turning into segfaults when using Lean functions which call into libuv
-
#13511 moves Async and Http from Internal to Std
-
#12151 introduces the Server module, an Async HTTP/1.1 server.
-
#13400 fixes the incorrect name
String.Pos.skipWhile_leto beString.Pos.le_skipWhile. -
#13398 removes private from H1.lean
-
#12146 introduces the H1 module, a pure HTTP/1.1 state machine that incrementally parses incoming byte streams and emits response bytes without side effects.
-
#13357 is based on a systematic review of all read-only operations on the default containers in core. Where sensible it applies specialize annotations on higher order operations that lack them or borrow annotations on parameters that should morally be borrowed (e.g. the container when iterating over it).
-
#13200 adds
prod(multiplicative fold) forList,Array, andVector, mirroring the existingsumAPI. Includes basic simp lemmas (prod_nil,prod_cons,prod_append,prod_singleton,prod_reverse,prod_push,prod_eq_foldl), Nat-specialized lemmas (prod_pos_iff_forall_pos_nat,prod_eq_zero_iff_exists_zero_nat,prod_replicate_nat), Int-specialized lemmas (prod_replicate_int), cross-type lemmas (prod_toArray,prod_toList), andPerm.prod_natwith grind patterns. -
#13273 adds a comprehensive public API for constructing maximally shared expression applications and performing beta reduction in the
Symframework. These functions were previously defined locally in the VC generator and cbv tactic, and are needed by downstreamSymM-based tools. -
#13155 verifies the
String.dropWhileandString.takeWhilefunctions. -
#13235 uses
std::memcmpforByteArrayBEqandDecidableEq. -
#13172 adds borrow annotations in
Std.Internal.UV.System.
Tactics
-
#13859 fixes a kernel rejection when a user-supplied pre-tactic like
clearinsym => mvcgen' with (clear h)rewrites the local context. -
#13857 implements the
dsimptactic for interactivesym =>mode. It also adds DSL for declaringdsimpvariants. -
#13680 makes
mvcgen'usable as a step insidesym => …blocks. Leftover VCs become subgoals for subsequent grind steps;mvcgen' invariantsworks inline,mvcgen' invariants?is rejected. -
#13854 implements the syntax for declaring
dsimpvariants forSymM. -
#13793 extends the new tactic hints about type-incorrect goals at
instancestransparency with the type checking error message to assist with cases that are more complex than "inadvisableunfold". -
#13636 makes
simpa using hclose at reducible transparency rather than the ambient (default/semireducible) transparency used previously, makingsimpa using hmore predictable under changes to the simp set. The previous behaviour is available assimpa using! h(introduced in #13833). -
#13833 adds the
simpa ... using! esyntax as a parallel form ofsimpa ... using e. At presentusing!behaves identically tousing— both close the goal at the ambient (default/semireducible) transparency. -
#13771 adds a new
impossible by ttactic combinator and wires it into the default suggestion set oftry?. -
#13825 implements a collection of reusable reduction
DSimprocs (beta,zeta,zetaAll,dsimpProj,dsimpMatch), exposing them as public so callers can compose them into their ownMethods, and fixing a few bugs. -
#13824 adds functions for simplifying binders in
Sym.dsimp. -
#13823 adds the basic infrastructure for a
dsimpinSymM. -
#13812 fixes
mconstructor,mleft, andmrightfailing insidemhaveblocks (#13691), andmspecializefailing after amrevert; mintroround trip. Both cases stem from hypothesis-namingExpr.mdataleaking from hypothesis-conjunction leaves into non-leaf positions (an inner target, or the antecedent of anSPred.imptarget), where downstream pattern matches did not see through it. -
#13766 moves the
evalSuggestcombinator and trace-handler dispatch from a hardcodedmatchon syntax kinds to the existingtryTacticElabAttributeregistration mechanism, bringingtry?'s extensibility model in line with normal tactics and interactivegrind. -
#13774 makes
try?'sexpandUserTacticwalk the info tree forTryThisInfonodes (introduced in #10524) instead of parsing the renderedTry this:message text. The previous approach scraped lines prefixed with[apply]from the message log, which would break the moment that wire format changed. -
#13430 makes an empty
byblock runtry?in the background and surface its suggestions, while still producing the usual unsolved-goals diagnostic. The implicittry?is informational only — it does not change elaboration behavior beyond emitting messages. Behaviour is controlled by a new optiontactic.tryOnEmptyBy, disabled by default for now; set it totrueto opt in. The default may flip in a future release. -
#13699 adds a new
grindconfiguration option,genLocal, that controls the maximum term generation for local theorems (e.g., hypotheses). It defaults to8, same value asgenand applies whenevergrindinstantiates a theorem whose origin is local rather than a declaration or user-provided term. Since users have little control over the patterns used for local theorems, a tighter generation bound is a reasonable default. -
#13698 improves the
grinddiagnostics output so that local hypotheses used as E-matching theorems show up with their user-facing names and instantiation counters, instead of being silently dropped or reported under an anonymouslocal.<idx>identifier. -
#13644 adds an experimental tactic
mvcgen'that will soon replacemvcgen. It has been reimplemented from the ground up using the newSymM-based framework for efficient symbolic evaluation and can outperformmvcgenby a factor of >100x for some synthetic benchmarks.mvcgen'aspires to be feature-complete withmvcgen. Known exceptions currently are join point sharing, introduction of local specs and smaller bugs. -
#13678 ensures that one can hover over the function name in fun_induction. Fixes #13673
-
#13665 replaces
Meta.mkCongrArgcall sites inhandleProjandsimplifyAppFnare replaced with directcongrArgconstructions that reuse types already in theSympointer cache. A few stray unqualifiedinferType/getLevel/isDefEqcalls in the same file are also routed through the cachedSymequivalents. -
#13640 adds a trace event emitted whenever a
dsimp(or rfl-onlysimp) rewrite fires because of a[backward_defeq]-tagged theorem (i.e., one that would not have applied withoutset_option backward.defeqAttrib.useBackward true). -
#13635 fixes a
Sym.simppanic ("unexpected kernel projection term during simplification") that triggered when matcher iota-reduction exposed kernelExpr.projterms via struct-eta. For example, adoblock with aforloop whose state is a tuple, whereSym.simpunfolds the equational lemma and then descends into a destructuring match. -
#13624 fixes a
grindcongruence-table invariant violation that could panic when anitebranch was internalized lazily (after the condition becameTrueorFalse) and that branch's equivalence class was later merged with another. -
#13625 fixes a
grindinternal error triggered whencast(orEq.rec,Eq.ndrec,Eq.recOn) is applied to an argument that has not yet been internalized.pushCastHEqswas emittinge ≍ abefore internalizing the args ofe, so therhsof the heq had no enode and the debug sanity check tripped. The call now runs after the args are internalized. -
#13623 fixes proof construction issues in the
grindprojection propagators. -
#13622 fixes another issue in the
grindAC invariant checker. -
#13614 fixes the invariant in
grindAC. equations in the todo queue are not fully simplified. -
#13612 improves the universe unifier used by
SymM. -
#13611 fixes an assertion failure in
Sym.simpwhen simplifying ahave-expression whose binder type depends on a preceding binder in the telescope. -
#13368 adds infrastructure to help diagnose cases where tactics like
unfoldleave the goal in a state that is type-correct only at.defaulttransparency, causingrw/simpto fail at.instancestransparency. -
#13593 disables model-based theory combination (
mbtc) ingrind'sNoopConfig, which is the base configuration used by the derived tacticslia,linarith,cutsat,order, andring. Without this fix, these tactics could engage in wasteful reasoning via theory combination, causing them to run for a long time (or hit the deterministic timeout) on problems they are not designed to solve. With this fix, these tactics fail quickly on out-of-scope problems, as expected. -
#13590 makes
lia(andgrind's arithmetic case-split heuristic) recognize implications whose antecedent is anAndorOrof arithmetic predicates as relevant case-split candidates. Previously,Arith.isRelevantPredonly matchedNot,LE,LT,Eq, andDvd. WithsplitImp := false(the default), implicationsp → qare added as split candidates only whenpis arith-relevant, so a hypothesis like(b ≤ e ∧ e < b + c → a ≤ e ∧ e < a + d)was never registered as a candidate. cutsat/lia would then find a satisfying assignment for the constraints it had been told about, but that assignment would not necessarily satisfy the original implication, yielding the bad counterexample reported in #13575. -
#13585 adds a
ringMaxDegreeconfiguration option (default1024) that bounds the maximum degree of polynomials processed by thegrindring solver. Equality constraints whose polynomial exceeds this threshold are discarded (with an issue reported once per goal), preventing pathological degree explosion on inputs such asr ^ (2 ^ 250 - 1). -
#13558 adds the option
grind.ematch.diagnostics, which tracks how E-matching theorem instances depend on each other. When enabled,grindrecords, for every new theorem instance, the set of previous instances whose generated terms participated in the match. This produces a hyper-graph{thm_1, ..., thm_n} => thmdescribing the provenance of each instantiation. -
#13560 fixes a bug in
propagateBetaEqs(inLean.Meta.Tactic.Grind.Beta) where new equalities/terms introduced by beta reduction were added to the goal without checking the generation threshold. The generation of the new fact is the maximum generation of the lambda, the functionf, and its arguments, plus one. Without the threshold check, beta reduction can cascade indefinitely on self-similar lambdas such as(fun b => f (b + 1)) = fun b => f b, which kept producingf n = f (n + 1)for everyn. The fix aggregates argument generations before the threshold check and bails out when the resulting generation reachesmaxGeneration. -
#13301 adds a
try? => tacsyntax that runsevalSuggestdirectly on a given tactic, useful for testing thetry?machinery in isolation. It also adds a server_interactive test (cancellation_par.lean) that demonstrates a cancellation bug with parallel tactic combinators. -
#13492 introduces stricter inference for the
@[defeq]attribute and a companion@[backward_defeq]attribute that preserves the pre-PR behavior as an opt-in. -
#13532 notifies satellite solvers about asserted equalities
lhs = rhseven thoughlhs = rhsis not internalized in the E-graph (an existing optimization). The notification lets solvers that do not inspect equivalence classes (such as the homomorphism extension) react to asserted equalities directly. It fires before the equivalence-class merge so that solvers that marklhsandrhsas their internal terms have them registered beforeSolvers.mergeTermsfiresprocessNewEq. -
#13476 refines how the
applytactic (and related tactics likerewrite) name and tag the remaining subgoals. Assigned metavariables are now filtered out before computing subgoal tags. As a consequence, when only one unassigned subgoal remains, it inherits the tag of the input goal instead of being given a fresh suffixed tag. -
#13474 fixes a bug in
sym =>interactive mode where goals whose metavariable was assigned byisDefEq(e.g. viaapply Eq.refl) were not pruned.pruneSolvedGoalspreviously only filtered out goals flagged as inconsistent, so an already-assigned goal would linger as an unsolved goal. It now also removes goals whose metavariable is already assigned. -
#13472 fixes a bug in
sym =>interactive mode where satellite solvers (lia,ring,linarith) would throw an internal error if their automaticintros + assertAllpreprocessing step already closed the goal. Previously,evalCheckusedliftActionwhich discarded the closure result, so the subsequentliftGoalMcall failed due to the absence of a main goal.liftActionis now split so the caller can distinguish the closed and subgoals cases and skip the solver body when preprocessing already finished the job. -
#13453 fixes a kernel error in
grindwhen propagating aNatequality to an order structure whose carrier type is notInt(e.g.Rat). The auxiliaryLean.Grind.Order.of_nat_eqlemma was specialized toInt, so the kernel rejected the application when the cast destination differed. -
#13451 fixes a bug in
Sym.introCore.finalizewhere the original metavariable was unconditionally assigned via a delayed assignment, even when no binders were introduced. As a result,Sym.introswould return.failedwhile the goal metavariable had already been silently assigned, confusing downstream code that relies onisAssigned(e.g. VC filters inmvcgen'). -
#13448 fixes a regression in
Sym.simpwhere rewrite rules whose LHS contains a lambda over a pattern variable (e.g.∃ x, a = x) failed to match targets with semantically equivalent structure. -
#13088 wires the
PowIdentitytypeclass (from https://github.com/leanprover/lean4/pull/13086) into thegrindring solver's Groebner basis engine. -
#13086 adds a
Lean.Grind.PowIdentitytypeclass stating thatx ^ p = xfor all elements of a commutative semiring, withpas anoutParam. -
#13289 adds the shared infrastructure for arithmetic normalization in
Sym.Arith/, laying the groundwork for bothSym.simp's arith pre-simproc and the eventual unification of grind'sCommRingmodule. -
#13272 extends the sym canonicalizer to apply reductions (projection, match/ite/cond, Nat arithmetic) in all positions, not just inside types. Previously, a value
vappearing in a typeT(v)could remain unreduced whileT(v)was normalized, breaking the invariant that definitionally equal types are structurally identical after canonicalization. -
#13271 refactors instance canonicalization in the sym canonicalizer to properly handle `Grind.nestedProof` and `Grind.nestedDecidable` markers. Previously, the canonicalizer would report an issue when it failed to resynthesize propositional instances that were provided by `grind` itself or by the user via `haveI`. Now, resynthesis failure gracefully falls back to the original instance in value positions, while remaining strict inside types.
-
#13202 fixes a heartbeat timeout from an environment extension at the end of the file that cannot be avoided by raising the limit.
Compiler
-
#13796 optimizes
String.compareto turn it into 1 instead of 2memcmpcalls. -
#13788 generates specialized code for invoking
decon values whose shape is known. This puts branch prediction pressure offlean_dec_ref_coldas the shape of the constructor should now be compiled into the executable. -
#13669 optimizes
lean_dec_ref_coldby outlining the "freezing cold" path and performing a small microarchitecural optimization. The latter is better as it makes clear to LLVM that we believe the pointer to only use 48 bits. -
#13545 upgrades LLVM from version 19 to version 22. This brings general performance improvements of up to 5% instructions depending on benchmark.
-
#13493 ensures that
importgracefully processesEINTRerrors from the filesystem. -
#13464 replaces
exit(-1)with_exit(-1)in the forked child branches oflean_io_process_spawn(thechdirfailure andexecvpfailure paths).exitflushes inherited C stdio buffers, which share underlying file descriptors with the parent. If the parent had a file handle open with unflushed data, that data would be written to the file in the child and then again when the parent later flushes, resulting in duplicated output._exitskips the stdio flush, so the parent's buffered writes are no longer duplicated into inherited files. -
#13435 fixes a bug in EmitC that can be caused by working with the string literal
"\x01abc"in Lean and causes a C compiler error. -
#13427 fixes two minor bugs in
io.cpp:-
A resource leak in a Windows error path of
Std.Time.Database.Windows.getNextTransition -
A buffer overrun in
IO.appPathon linux when the executable is a symlink at max path length.
-
-
#13421 fixes an issue in the expand reset reuse pass that causes segfaults in very rare situations.
-
#13409 specialize qsort properly onto the lt function
-
#13401 adds the option
LEAN_MI_SECUREto our CMake build. It can be configured with values0through4. Every increment enables additional memory safety mitigations in mimalloc, at the cost of 2%-20% instruction count, depending on the benchmark. The option is disabled by default in our release builds as most of our users do not use the Lean runtime in security sensitive situations. Distributors and organization deploying production Lean code should consider enabling the option as a hardening measure. The effects of the various levels can be found at https://github.com/microsoft/mimalloc/blob/v2.2.7/include/mimalloc/types.h#L56-L60. -
#13392 fixes a heap buffer overflow in
lean_io_prim_handle_readthat was triggered through an integer overflow in the size computation of an allocation. In addition it places several checked arithmetic operations on all relevant allocation paths to have potential future overflows be turned into crashes instead. The offending code now throws an out of memory error instead. -
#13384 fixes a compiler panic when a structure constructor receives a noncomputable instance as an instance-implicit argument.
-
#13234 fixes a build issue when Lean is not linked against libuv.
-
#13233 fixes runtime build issues when
LEAN_MULTI_THREADis not set. -
#13270 adds
Runtime.hold, which ensures its argument remains alive until the callsite by holding a reference to it. This can be useful for unsafe code (such as an FFI) that relies on a Lean object not being freed until after some point in the program. -
#13258 adds a
Core.checkInterruptedcall incheckInferTypeCacheon cache miss, allowing cancellation to be detected during large type inference traversals. Previously,inferTypeImpcould run for >100ms without any interruption check when processing large expressions (e.g. BVDecide proof terms), making IDE cancellation unresponsive. -
#13242 fixes the compiler handling of pattern matching on the
Stringconstructor to conform to the newStringrepresentation. -
#13128 fixes the Windows dev build by using
CMAKE_RELATIVE_LIBRARY_OUTPUT_DIRECTORYinstead of the hardcodedlib/leanpath for the Lake plugin. On Windows, DLLs must be placed next to executables inbin/, but the plugin path was hardcoded tolib/lean, causing stage0 DLLs to not be found.
Pretty Printing
-
#13761 fixes an issue where the
pp.universesoption would cause constants with no universes to not use unexpanders or dot notation. For example,p ↔ qwould pretty print asIff p qeven thoughIffhas no universe levels. -
#13446 improves metavariable pretty printing and their hovers in the InfoView. The hovers in the InfoView now include information about specific metavariables — it includes information such as the kind of the metavariable, whether it is a blocked delayed assignment and which metavariables it is blocked on, and the differences in what variables exist the metavariable's local context. Additionally, named metavariables now pretty print with tombstones if they are inaccessible. Delayed assignment pretty printing now more reliably follows chains of assignments to find the pending metavariable.
-
#13438 makes the universe level pretty printer instantiate level metavariables when
pp.instantiateMVarsis true. -
#13030 improves pretty printing of level metavariables: they now print with a per-definition index rather than their per-module internal identifiers. Furthermore,
+is printed uniformly in level expressions with surrounding spaces. Breaking metaprogramming change: level pretty printing should usedelabLevelorMessageData.ofLevel; functions such asformatortoStringdo not have access to the indices, since they are stored in the current metacontext. Absent index information, metavariables print with the raw internal identifier as?_mvar.nnn. Note: The heartbeat counter also increases quicker due to counting allocations that record level metavariable indices. In some tests we needed to increasemaxHeartbeatsby 20–50% to compensate, without a corresponding slowdown.
Documentation
Server
-
#13525 adds
FromJson/ToJsoninstances forUnit- encoded as{}- and documentation forFromJson/ToJson. -
#13260 adds server-side support for incremental diagnostics via a new
isIncrementalfield onPublishDiagnosticsParamsthat is only used by the language server when clients setincrementalDiagnosticSupportinLeanClientCapabilities. -
#13348 fixes a bug where tactic auto-completion would produce tactic completion items in the entire trailing whitespace of an empty tactic block. Since #13229 further restricted top-level
byblocks to be indentation- sensitive, this PR adjusts the logic to only display completion items at a "proper" indentation level. -
#13257 adds test infrastructure and tests for tactic completion in empty
byblocks.
Lake
-
#13843 makes
lake lint --builtin-lintimport module-system targets at the public (OLeanLevel.exported) level instead ofprivate. Environment linters now lint the public surface of such modules, matching how downstream consumers see them. Non-module targets retain their previous behaviour (privatelevel), and text-linter warnings recorded vialintLogExtare preserved across the level change because that extension stores uniform OLean entries. -
#13563 makes
Glob.ofString?public, allowing removing the last use ofopen privatefrom Mathlib. -
#13683 moves the compiled Lake configurations (e.g.,
lakefile.olean) from the package's.lake/configdirectory to the workspace's.lake/config. This removes a potential source contention between workspaces sharing a dependency. -
#13601 changes Lake's module import graph processing to await the completion of any
needstargets or other extra dependencies (such as cloud releases). This both enables theneedstargets to influence header processing and prevents them from racing with said processing. -
#13600 fixes a Lake issue where the IR for a
meta import's transitive imports was not included in the import artifacts Lake provided to Lean (e.g., via--setup). When using the Lake artifact cache, this could produce "missing data file" errors due to absent IR. -
#13559 fixes a race condition in the Lake build monitor's draining of the job queue.
-
#13513 extends
lake lint --builtin-lintto also support text linters (i.e. those usinglogLint/logLintIf), in addition to the environment linters added in #13431. Text-linter warnings emitted during the build are persisted into each module's.oleanvia a newLean.Linter.lintLogExtenvironment extension;lake lintre-runs the build for the target modules and reads the entries back, reporting them alongside the environment linter output. -
#13516 adds
namespace LaketoLake.Util.Opaque, which was missing it. This is technically a breaking change for any code which usedOpaquewithoutopen Lake, but hopefully no one was doing that. -
#13500 adds a check for empty
lake buildinvocations (as an empty build usually indicates a misconfiguration). Builds with no jobs will now print "Nothing to build." and invocations oflake buildwith no default targets configured will produce a warning. This will be promoted to an error in the future. The warning (and future error) can be suppressed with the new--allow-emptyCLI option. -
#13431 adds builtin environment linting support to Lake, accessible via
lake lintflags. It also introduces two builtin linters upstreamed from Mathlib (defLemmaandcheckUnivs) and abuiltinLintpackage configuration option. -
#13456 adds a type abbreviation
GitRevto Lake, which is used forStringvalues that signify Git revisions. Such revisions may be a SHA1 commit hash, a branch name, or one of Git's more complex specifiers. -
#13423 adds
JobAction.reuseandJobAction.unpackwhich provide more information captions for what a job is doing for the build monitor.reuseis set when using an artifact from the Lake cache,unpackis set when unpacking module.ltararchives and release (Reservoir or GitHub) archives. -
#13393 adds a basic support for
lake builtin-lintcommand that is used to run environment linters and in the future will be extend to deal with the core syntax linters. -
#13340 fixes a Lake issue where library builds would not produce informative errors about bad imports (unlike module builds).
-
#13282 introduces
LakefileConfig, which can be constructed from a Lake configuration file without all the information required to construct a fullPackage. Also, workspaces now have a well-formedness property attached which ensures the workspace indices of its packages match their index in the workspace. Finally, the facet configuration map now has its own type:FacetConfigMap. -
#13277 fixes a public-facing typo in a function name:
Module.checkArtifactsExsist->Module.checkArtifactsExist.
Other
-
#13185 adds new incremental module serialization functions that save/load a single module at a time with explicit sharing via dep regions and compactor state, generalizing the existing batch saveModuleDataParts API.
-
#13740 extends
lake shake --explainto also cover reasons for keeping imports that go beyond direct references, such as shake annotations. -
#13530 adds a
trace.profiler.serveoption that, when enabled, serves the Firefox Profiler-compatible profile JSON on an ephemeral127.0.0.1port and openshttps://profiler.firefox.com/from-url/...in the user's default browser, à lasamply. The server shuts down once the profile has been fetched. -
#13630 fixes an "Unknown constant" error when
set_option diagnostics trueis enabled in module mode under apublic section. Diagnostic output may reference private declarations such as_match_*and_sparseCasesOn_*that are recorded in unfold counters; constructing the message previously failed because the environment was in exporting mode and could not resolve those names. The diagnostic-printing paths inLean.Meta.Diagnostics.reportDiagandLean.Meta.Tactic.Simp.Diagnostics.reportDiagnow run underwithoutExporting. -
#13589 ensures that the
lean --error=tagflag actually sets a non-zero exit code on promoted errors. -
#13553 fixes a typo in the error message thrown by
runInitAttrswhen initializer execution has not been enabled. The message previously referred toenableInitializerExecution(singular), but the actual function isenableInitializersExecution(plural). -
#13520 extends the
grindhomomorphism demo with predicates to be applied atoms. -
#13499 fixes the architecture detection for
leantaron Linux aarch64, ensuring it is properly bundled with Lean. -
#13497 adds an example for the Lean hackathon in Paris. It demonstrates how users can implement https://hackmd.io/Qd0nkWdzQImVe7TDGSAGbA
-
#13132 adds a
linter.redundantVisibilityoption (defaulttrue) that warns when a visibility modifier has no effect because it matches the default for the current context:-
privateoutside apublic sectionin amodulefile, where declarations are already module-scoped by default -
publicin a non-modulefile or inside apublic section, where declarations are already public by default
-
-
#13211 adds an
unlock_limitscommand that setsmaxHeartbeats,maxRecDepth, andsynthInstance.maxHeartbeatsto 0, disabling all core resource limits. Also makesmaxRecDepth 0mean "no limit" (matching the existing behavior ofmaxHeartbeats 0). -
#13226 updates
release_checklist.pyto handle theCACHE STRING ""suffix on CMake version variables. TheCACHE STRINGformat was introduced in thereleases/v4.30.0branch, but the script's parsing wasn't updated to match, causing false failures.