Lean 4.21.0 (2025-06-30)
For this release, 295 changes landed. In addition to the 100 feature additions and 83 fixes listed below there were 2 refactoring changes, 4 documentation improvements, 6 performance improvements, 2 improvements to the test suite and 98 other changes.
Highlights
'Unknown identifier' code actions
-
#7665 and #8180 add support for code actions that resolve 'Unknown identifier' errors by either importing the missing declaration or by changing the identifier to one from the environment.
New Language Features
-
#8449 and #8516 upstream and extend the Mathlib
clear_valuetactic. Given a local definitionx : T := v, the tacticclear_value xreplaces it with a hypothesisx : T, or throws an error if the goal does not depend on the valuev. The syntaxclear_value (h : x = _)creates a hypothesish : x = _before clearing the value ofx. Any expression definitionally equal toxcan be used in place of the underscore. Furthermore,clear_value *clears all values that can be cleared, or throws an error if none can be cleared. -
#8512 adds a
value_of% identterm that elaborates to the value of the local or global constantident. This is useful for creating definition hypotheses:let x := ... complicated expression ... have hx : x = value_of% x := rfl
-
#8450 adds a feature to the
substtactic so that whenx : X := vis a local definition,subst xsubstitutesvforxin the goal and removesx. Previously the tactic would throw an error. -
#8037 introduces a
noConfusionTypeconstruction that’s sub-quadratic in size, and reduces faster. The previousnoConfusionconstruction with two nestedmatchstatements is quadratic in size and reduction behavior. Using some helper definitions, a linear size construction is possible. -
#8104 makes
fun_inductionandfun_cases(try to) unfold the function application of interest in the goal. The old behavior can be enabled withset_option tactic.fun_induction.unfolding false. Forfun_casesthis does not work yet when the function’s result type depends on one of the arguments, see issue #8296. -
#8171 omits cases from functional induction/cases principles that are implemented
by contradiction(or, more generally,False.elim,absurdor `noConfusion). Breaking change in the sense that there are fewer goals to prove after using functional induction. -
#8106 adds a
register_linter_setcommand for declaring linter sets. ThegetLinterValuefunction now checks if the present linter is contained in a set that has been enabled (using theset_optioncommand or on the command line). -
#8267 makes
#guard_msgsto treattracemessages separate frominfo,warninganderror. It also introduces the ability to say#guard_msgs (pass info), like(drop info)so far, and also adds(check info)as the explicit form of(info), for completeness.
Library Highlights
-
#8358 introduces a very minimal version of the new iterator library. It comes with list iterators and various consumers, namely
toArray,toList,toListRev,ForIn,fold,foldManddrain. All consumers also come in a partial variant that can be used without any proofs. This limited version of the iterator library generates decent code, even with the old code generator. -
#7352 reworks the
simpset around theIdmonad, to not elide or unfoldpureandId.run -
#8313 changes the definition of
Vectorso it no longer extendsArray. This preventsArrayAPI from "leaking through".
Other Highlights
-
Performance optimizations in
dsimp:-
#6973 stops
dsimpfrom visiting proof terms, which should makesimpanddsimpmore efficient. -
#7428 adds a
dsimpcache tosimp. Previously eachdsimpcall fromsimpstarted with a fresh cache. As a result, time spent insimpwhile compiling Mathlib is reduced by over 45%, giving an overall 8% speedup to Mathlib compilation.
-
-
#8221 adjusts the experimental module system to not export the bodies of
defs unless opted out by the new attribute@[expose]on thedefor on a surroundingsection. -
#8559 and #8560 fix an adversarial soundness attack described in #8554. The attack exploits the fact that
assert!no longer aborts execution, and that users can redirect error messages.
Language
-
#6973 stops
dsimpfrom visiting proof terms, which should makesimpanddsimpmore efficient. -
#7428 adds a
dsimpcache tosimp. Previously eachdsimpcall fromsimpstarted with a fresh cache. As a result, time spent insimpwhile compiling Mathlib is reduced by over 45%, giving an overall 8% speedup to Mathlib compilation. -
#7631 fixes
Lean.Level.mkIMaxAux(mk_imaxin the kernel) such thatimax 1 ureduces tou. -
#7977 adds basic support for eta-reduction to
grind. -
#8002 fixes an issue where "go to definition" for variables generalized by the
inductionandcasestactic did not work. Closes #2873. -
#8024 adds the
--setupoption to theleanCLI. It takes a path to a JSON file containing information about a module's imports and configuration, superseding that in the module's own file header. This will be used by Lake to specify paths to module artifacts (e.g., oleans and ileans) separate from theLEAN_PATHschema. -
#8037 introduces a
noConfusionTypeconstruction that’s sub-quadratic in size, and reduces faster. -
#8104 makes
fun_inductionandfun_cases(try to) unfold the function application of interest in the goal. The old behavior can be enabled withset_option tactic.fun_induction.unfolding false. Forfun_casesthis does not work yet when the function’s result type depends on one of the arguments, see issue #8296. -
#8106 adds a
register_linter_setcommand for declaring linter sets. ThegetLinterValuefunction now checks if the present linter is contained in a set that has been enabled (using theset_optioncommand or on the command line). -
#8169 makes the whitespace handling in the syntax of
omitandincludeconsistent withvariable. -
#8171 omits cases from functional induction/cases principles that are implemented
by contradiction(or, more generally,False.elim,absurdor `noConfusion). Breaking change in the sense that there are fewer goals to prove after using functional induction. -
#8196 improves the E-matching pattern inference procedure in
grind. Consider the following theorem:@[grind →] theorem eq_empty_of_append_eq_empty {xs ys : Array α} (h : xs ++ ys = #[]) : xs = #[] ∧ ys = #[] := append_eq_empty_iff.mp hBefore this PR,
grindinferred the following pattern:@HAppend.hAppend _ _ _ _ #2 #1
Note that this pattern would match any
++application, even if it had nothing to do with arrays. With this PR, the inferred pattern becomes:@HAppend.hAppend (Array #3) (Array _) (Array _) _ #2 #1
With the new pattern, the theorem will not be considered by
grindfor goals that do not involveArrays. -
#8198 fixes an issue in the theory propagation used in
grind. When two equivalence classes are merged, the core may need to push additional equalities or disequalities down to the satellite theory solvers (e.g.,cutsat,comm ring, etc). Some solvers (e.g.cutsat) assume that all of the core’s invariants hold before they receive those facts. Propagating immediately therefore risks violating a solver’s pre-conditions midway through the merge. To decouple the merge operation from propagation and to keep the core solver-agnostic, this PR adds the helper typePendingTheoryPropagation. -
#8208 reduces the need for defeq in frequently used bv_decide rewrite by turning them into simprocs that work on structural equality instead. As the intended meaning of these rewrites is to simply work with structural equality anyways this should not change the proving power of
bv_decide's rewriter but just make it faster on certain very large problems. -
#8209 fixes a nondeterminism issue in the
grindtactic. It was a bug in the model-based theory combination module. -
#8221 adjusts the experimental module system to not export the bodies of
defs unless opted out by the new attribute@[expose]on thedefor on a surroundingsection. -
#8224 adds diagnostic information for the commutative ring procedure in
grind. -
#8226 fixes the
simplifyBasisprocedure in the commutative ring procedure ingrind. -
#8231 changes the behaviour of
apply?so that thesorryit uses to close the goal is non-synthetic. (Recall that correct use of synthetic sorries requires that the tactic also generates an error message, which we don't want to do in this situation.) This change defends against the problem reported in #8212. -
#8232 fixes elaboration of constants in the
rewritetactic. previously,rw [eq_self]would elaborateeq_selftwice, and add it to the infotree twice. This would lead to the "Expected type" being delaborated with an unknown universe metavariable. -
#8241 changes the behavior of the
renametactic to skip over implementation detail hypotheses when finding a hypothesis to rename. -
#8254 fixes unintended inlining of
ToJson,FromJson, andReprinstances, which was causing exponential compilation times inderivingclauses for large structures. -
#8259 clarifies the invalid field notation error when projected value type is a metavariable.
-
#8260 clarifies the invalid dotted identifier notation error when the type is a sort.
-
#8261 adjusts the error message when
applyfails to unify. It is clearer about distinguishing the term being applied and the goal, as well as distinguishing the "conclusion" of the given term and the term itself. -
#8262 improves the type-as-hole error message. Type-as-hole error for theorem declarations should not admit the possibility of omitting the type entirely.
-
#8264 rewords the
application type mismatcherror message by more specifically mentioning that the problem is with the final argument. This is useful when the same argument is passed to the function multiple times. -
#8267 makes
#guard_msgsto treattracemessages separate frominfo,warninganderror. It also introduce the ability to say#guard_msgs (pass info, like(drop info)so far, and also adds(check info)as the explicit form of(info), for completeness. -
#8270 makes the enum pass of
bv_decidehandle enum types that are universe polymorphic. -
#8271 changes
addPPExplicitToExposeDiffto show universe differences and to visit into projections, e.g.:error: tactic 'rfl' failed, the left-hand side (Test.mk (∀ (x : PUnit.{1}), True)).1 is not definitionally equal to the right-hand side (Test.mk (∀ (x : PUnit.{2}), True)).1for
inductive Test where | mk (x : Prop)
-
#8275 ensures the congruence closure in
grindand find non-dependent arrow congruences. That is, it can apply theimplies_congrtheorem. -
#8276 adds the instances
Grind.CommRing (Fin n)andGrind.IsCharP (Fin n) n. New tests:example (x y z : Fin 13) : (x + y + z) ^ 2 = x ^ 2 + y ^ 2 + z ^ 2 + 2 * (x * y + y * z + z * x) := by grind +ring -
#8277 improves the generation of
.induct_unfoldingby rewritingmatchstatements more reliably, using the new “congruence equations” introduced in #8284. Fixes #8195. -
#8280 the support for arrows in the congruence closure procedure used in
grind. -
#8281 improves the module used to prove auxiliary type cast equalities in
grind. -
#8284 adds a new variant of equations for matchers, namely “congruence equations” that generalize the normal matcher equations. They have unrestricted left-hand-sides, extra equality assumptions relating the discriminiants with the patterns and thus prove heterogenous equalities. In that sense they combine congruence with rewriting. They can be used to rewrite matcher applications where, due to dependencies,
simpwould fail to rewrite the discriminants, and will be used when producing the unfolding induction theorems. -
#8285 fixes “declaration has free variables” errors when generating a splitter for a match statement with named patterns. Fixes #8274.
-
#8299 implements a missing preprocessing step in
grind: abstract metavariables in the goal -
#8301 unfolds functions in the unfolding induction principle properly when they use
bif(a.k.a.Bool.cond). -
#8302 lets
casesfail gracefully when the motive has an complex argument whose type is dependent type on the targets. While theinductiontactic can handle this well,casesdoes not. This change at least gracefully degrades to not instantiating that motive parameter. See issue #8296 for more details on this issue. -
#8303 fixes missing occurrences of
foldProjsingrind. -
#8306 makes it possible for
bv_decideto tackle situations for its enum type preprocessing where the enums themselves are use in a dependently type context (for example inside of aGetElembody) and thus not trivially accessible tosimpfor rewriting. To do this we dropGetElemonBitVecas well asditeas early as possible in the pipeline. -
#8321 lets the termination argument inference consider negations of Nat comparisons. Fixes #8257.
-
#8323 adds support for bv_decide to understand
BitVec.reversein bitblasting. -
#8330 improves support for structure extensionality in
grind. It now uses eta expansion for structures instead of the extensionality theorems generated by[ext]. Examples:opaque f (a : Nat) : Nat × Bool
-
#8338 improves the error messages displayed in
inductivedeclarations when type parameters are invalid or absent. -
#8341 fixes the
propagateCtorconstraint propagator used ingrind. -
#8343 splits
Lean.Grind.CommRinginto 4 typeclasses, for semirings and noncommutative rings. This does not yet change the behaviour ofgrind, which expects to find all 4 typeclasses. Later we will make some generalizations. -
#8344 fixes term normalization issues in
grind, and the new optiongrind +etaStruct. -
#8347 adds draft typeclasses for
grindto process facts about ordered modules. These interfaces will evolve as the implementation develops. -
#8354 makes sure that when generating the unfolding functional induction theorem,
mdatadoes not get in the way. -
#8356 tries harder to clean internals of the argument packing of n-ary functions from the functional induction theorem, in particular the unfolding variant
-
#8359 improves the functional cases principles, by making a more educated guess which function parameters should be targets and which should remain parameters (or be dropped). This simplifies the principles, and increases the chance that
fun_casescan unfold the function call. -
#8361 fixes a bug in the
casestacic introduced in #3188 that arises when cases (not induction) is used with a non-atomic expression in using and the argument indexing gets confused. -
#8363 unifies various ways of naming auxiliary declarations in a conflict-free way and ensures the method is compatible with diverging branches of elaboration such as parallelism or Aesop-like backtracking+replaying search.
-
#8365 fixes the transparency mode for ground patterns. This is important for implicit instances. Here is a mwe for an issue detected while testing
grindin Mathlib.example (a : Nat) : max a a = a := by grind
-
#8368 improves the error messages produced by invalid pattern-match alternatives and improves parity in error placement between pattern-matching tactics and elaborators.
-
#8369 fixes a type error at
instantiateTheoremfunction used ingrind. It was failing to instantiate theorems such astheorem getElem_reverse {xs : Array α} {i : Nat} (hi : i < xs.reverse.size) : (xs.reverse)[i] = xs[xs.size - 1 - i]'(by simp at hi; omega)in examples such as
example (xs : Array Nat) (w : xs.reverse = xs) (j : Nat) (hj : 0 ≤ j) (hj' : j < xs.size / 2) : xs[j] = xs[xs.size - 1 - j]generating the issue
[issue] type error constructing proof for Array.getElem_reverse when assigning metavariable ?hi with ‹j < xs.toList.length› has type j < xs.toList.length : Prop but is expected to have type j < xs.reverse.size : Prop -
#8375 ensures that using
mapErrorto expand an error message usesaddMessageContextto include the current context, so that expressions are rendered correctly. Also adds apreprendErrorvariant with a more convenient argument order for the common cases of prepending-and-indenting. -
#8403 adds missing monotonicity lemmas for universal quantifiers, that are used in defining (co)inductive predicates.
-
#8410 fixes a case-splitting heuristic in
grindand simplifies the proof for testgrind_palindrome2.lean. -
#8412 fixes the
markNestedProofspreprocessor used ingrind. There was a missing case (e.g.,Expr.mdata) -
#8413 implements normalization rules that pull universal quantifiers across disjunctions. This is a common normalization step performed by first-order theorem provers.
-
#8417 introduces
Lean.Grind.Field, proves that aIsCharP 0field satisfiesNoNatZeroDivisors, and sets up some basic (currently failing) tests forgrind. -
#8426 adds the attribute
[grind?]. It is like[grind]but displays inferred E-matching patterns. It is a more convinient than writing. Thanks @kim-em for suggesting this feature.set_option trace.grind.ematch.pattern true
also improves some tests, and adds helper function
ENode.isRoot. -
#8429 adds
Lean.Grind.Ring.IsOrdered, and cleans up the ring/module grind API. These typeclasses are at present unused, but will support future algorithmic improvements ingrind. -
#8437 fixes
splitin the presence of metavariables in the target. -
#8438 ensures that
grinddiagnostics are obtained even whenmaxHeartbeatsis reached. also removes some dead code. -
#8440 implements non-chronological backtracking for the
grindtactic. This feature ensures thatgrinddoes not need to process irrelevant branches after performing a case-split that is not relevant. It is not just about performance, but also the size of the final proof term. The new test demonstrates this feature in practice.-- In the following test, the first 8 case-splits are irrelevant, -- and non-choronological backtracking is used to avoid searching -- (2^8 - 1) irrelevant branches /-- trace: [grind.split] p8 ∨ q8, generation: 0 [grind.split] p7 ∨ q7, generation: 0 [grind.split] p6 ∨ q6, generation: 0 [grind.split] p5 ∨ q5, generation: 0 [grind.split] p4 ∨ q4, generation: 0 [grind.split] p3 ∨ q3, generation: 0 [grind.split] p2 ∨ q2, generation: 0 [grind.split] p1 ∨ q1, generation: 0 [grind.split] ¬p ∨ ¬q, generation: 0 -/ #guard_msgs (trace) in set_option trace.grind.split true in theorem ex : p ∨ q → ¬ p ∨ q → p ∨ ¬ q → ¬ p ∨ ¬ q → p1 ∨ q1 → p2 ∨ q2 → p3 ∨ q3 → p4 ∨ q4 → p5 ∨ q5 → p6 ∨ q6 → p7 ∨ q7 → p8 ∨ q8 → False := by grind (splits := 10) -
#8443 adds the lemmas about ordered rings and ordered fields which will be needed by the new algebraic normalization components of
grind. -
#8449 upstreams and extends the Mathlib
clear_valuetactic. Given a local definitionx : T := v, the tacticclear_value xreplaces it with a hypothesisx : T, or throws an error if the goal does not depend on the valuev. The syntaxclear_value x with hcreates a hypothesish : x = vbefore clearing the value ofx. Furthermore,clear_value *clears all values that can be cleared, or throws an error if none can be cleared. -
#8450 adds a feature to the
substtactic so that whenx : X := vis a local definition,subst xsubstitutesvforxin the goal and removesx. Previously the tactic would throw an error. -
#8466 fixes another instance of the
grindissue "unexpected kernel projection term during internalization". -
#8472 avoids name resolution blocking on the elaboration of a theorem's proof when looking up the theorem name.
-
#8479 implements hash-consing for
grindthat takes alpha equivalence into account. -
#8483 ensures
grindreuses thesimpcache between different calls. Recall thatgrindusessimpto normalize terms during internalization. -
#8491 fixes the behavior of
simp_all?andsimp_all?!, aligning them withsimp_allandsimp_all!respectively. -
#8506 implements
match-expressions ingrindusingmatchcongruence equations. The goal is to minimize the number ofcastoperations that need to be inserted, and avoidcastover functions. The new approach supportmatch-expressions of the formmatch h : ... with .... -
#8512 adds a
value_of% identterm that elaborates to the value of the local or global constantident. This is useful for creating definition hypotheses:let x := ... complicated expression ... have hx : x = value_of% x := rfl
-
#8516 is a followup to #8449 to refine the syntax of
clear_value. The syntax for adding equality hypotheses before clearing values is nowclear_value (h : x = _). Any expression definitionally equal toxcan be used in place of the underscore. -
#8536 fixes the support for
LawfulBEqandBEqingrind. -
#8541 ensures that for any nested proof
h : pin a goal, we propagate thatpis true in thegrindtactic. -
#8542 fixes two inappropriate uses of
whnfDingrind. They were potential performance foot guns, and were producing unexpected errors sincewhnfDis not consistently used (and it should not be) in all modules. -
#8544 implements support for over-applied
iteandditeapplications in thegrindtactic. It adds support for propagation and case-split. -
#8549 fixes the hash function used to implement congruence closure in
grind. The hash of anExprmust not depend on whether the expression has been internalized or not. -
#8564 simplifies the interface between the
grindcore and the cutsat procedure. Before this PR, core would try to minimize the number of numeric literals that have to be internalized in cutsat. This optimization was buggy (seegrind_cutsat_zero.leantest), and produced counterintuitive counterexamples. -
#8569 adds support for generalized E-match patterns to arbitrary theorems.
-
#8570 fixes some issues in the E-matching generalized pattern support after the update stage0.
-
#8572 adds some generalized
Optiontheorems forgrind. The avoidcastsoperations during E-matching. -
#8576 sets
ring := trueby default ingrind. It also fixes a bug in the reification procedure, and improves the term internalization in the ring and cutsat modules.
Library
-
#7352 reworks the
simpset around theIdmonad, to not elide or unfoldpureandId.run -
#7995 adds a verification of
Array.qsortproperties, trying to usegrindandfun_inductionwhere possible. Currently this is in thetests/folder, but oncegrindis ready for production use we will move it out into the library. -
#8182 adds
ofList_eq_insertMany_emptylemmas for all the hash/tree map types, with the exception ofStd.HashSet.Raw.ofList_eq_insertMany_empty. -
#8188 takes the existing
getElem_mapstatements forHashMapvariants (alsogetElem?,getElem!, andgetDstatements), adds a prime to their name and an explanatory comment, and replaces the unprimed statement with a simpler statement that is only true withLawfulBEqpresent. The original statements which were simp lemmas are now low priority simp lemmas, so the nicer statements should fire whenLawfulBEqis available. -
#8202 adds an inference that was repeatedly needed when proving
BitVec.msb_sdiv, and is the symmetric version ofBitVec.one_eq_zero_iff -
#8206 shows that negating a bitvector created from a natural number equals creating a bitvector from the the negative of that number (as an integer).
-
#8216 completes adding
@[grind]annotations forOptionlemmas, and incidentally fills in someOptionAPI gaps/defects. -
#8218 continues adding
@[grind]attributes for List/Array/Vector, particularly to the lemmas involving thetoList/toArrayfunctions. -
#8246 add
@[grind]annotations for HashMap and variants. -
#8272 adds lemmas about the length and use of
[]?on results ofList.intersperse. -
#8291 changes the statements of
Finlemmas to use[NeZero n] (i : Fin n)rather than(i : Fin (n+1))where possible. -
#8298 adds various
Optionlemmas and definesOption.filterMfor applicative functors. -
#8313 changes the definition of
Vectorso it no longer extendsArray. This preventsArrayAPI from "leaking through". -
#8315 splits
Std.Classes.OrdintoStd.Classes.Ord.Basic(with few imports) andStd.Classes.Ord.SIntandStd.Classes.Ord.Vector. These changes avoid importingInit.Data.BitVec.Lemmasunnecessarily into various basic files. As the new import-only fileStd.Classes.Ordimports all three of these, end-users are not affected. -
#8318 is follow-up to #8272, combining the conditional lemmas for
getElem_intersperseinto a single lemma with anifon the RHS. -
#8327 adds
@[grind]annotations to the genericgetElem?_eq_none_iff,isSome_getElem?, andget_getElem?. -
#8328 adds the
@[grind =]attribute to allcontains_iff_memlemmas. -
#8331 improves the docstring for
PlainDateTime.nowand its variants. -
#8346 adds some missing lemmas about consequences of positivity/non-negativity of
a * b : Int. -
#8349 fixes the signature of the intended
Inhabitedinstance forExtDHashMap. -
#8357 adds variants of
dite_eq_left_iffthat will be useful in a future PR. -
#8358 introduces a very minimal version of the new iterator library. It comes with list iterators and various consumers, namely
toArray,toList,toListRev,ForIn,fold,foldManddrain. All consumers also come in a partial variant that can be used without any proofs. This limited version of the iterator library generates decent code, even with the old code generator. -
#8378 improves and extends the api around
OrdandOrdering. -
#8379 adds missing
Optionlemmas. -
#8380 provides simple lemmas about
toArray,toListandtoListRevfor the iterator library. -
#8384 provides lemmas about the behavior of
step,toArray,toListandtoListRevon list iterators created withList.iterandList.iterM. -
#8389 adds the
List/Array/Vector.ofFnM, the monadic analogues ofofFn, along with basic theory. -
#8392 corrects some
Arraylemmas to be aboutArraynotList. -
#8397 cleans up many duplicate instances (or, in some cases, needlessly duplicated
def X := ...; instance Y := X). -
#8399 adds variants of
HashMap.getElem?_filterthat assumeLawfulBEqand have a simpler right-hand-side.simpcan already achieve these, via rewriting withgetKey_equnder the lambda. Howevergrindcan not, and these lemmas helpgrindwork withHashMapgoals. There are variants for all variants ofHashMap,getElem?/getElem/getElem!/getD, and forfilterandfilterMap. -
#8405 provides lemmas about the loop constructs
ForIn,fold,foldManddrainand their relation to each other in the context of iterators. -
#8418 provides the
takeiterator combinator that transforms any iterator into an iterator that stops after a given number of steps. The change contains the implementation and lemmas. -
#8422 adds
LTandDecidableLTinstances forStd.Time.TimestampandStd.Time.Duration. -
#8434 adds the equivalent of
List.take_consaboutList.drop. -
#8435 upstreams the
LawfulMonadLift(T)classes, lemmas and instances from Batteries into Core because the iterator library needs them in order to prove lemmas about themapMoperator, which relies onMonadLiftT. -
#8445 adds a
@[simp]lemma, and comments explaining that there is intentionally no verification API forVector.take,Vector.drop, orVector.tail, which should all be rewritten in terms ofVector.extract. -
#8446 adds basic
@[grind]annotations forTreeMapand its variants. Likely more annotations will be added after we've explored some examples. -
#8451 provides the iterator combinator
filterMapin a pure and monadic version and specializationsmapandfilter. This new combinator allows to apply a function to the emitted values of a stream while filtering out certain elements. -
#8460 adds further
@[grind]annotations forOption, as follow-up to the recent additions to theOptionAPI in #8379 and #8298. -
#8465 adds further lemmas about
LawfulGetElem, including marking some with@[grind]. -
#8470 adds
@[simp]togetElem_pos/neg(similarly forgetElem!). These are often already simp lemmas for concrete types. -
#8482 adds preliminary
@[grind]annotations forList.PairwiseandList.Nodup. -
#8484 provides the iterator combinator
zipin a pure and monadic version. -
#8492 adds
simplemmas fortoInt_*andtoNat_*with arithmetic operation given the hypothesis of no-overflow (toNat_add_of_not_uaddOverflow,toInt_add_of_not_saddOverflow,toNat_sub_of_not_usubOverflow,toInt_sub_of_not_ssubOverflow,toInt_neg_of_not_negOverflow,toNat_mul_of_not_umulOverflow,toInt_mul_of_not_smulOverflow). In particular, these aresimpsince (1) therhsis strictly simpler than thelhsand (2) this version is also simpler than the standard operation when the hypothesis is available. -
#8493 provides the iterator combinators
takeWhile(forwarding all emitted values of another iterator until a predicate becomes false)dropWhile(dropping values until some predicate on these values becomes false, then forwarding all the others). -
#8497 adds preliminary grind annotations for
List.Sublist/IsInfix/IsPrefix/IsSuffix, along with test cases. -
#8499 changes the definition of
Array.ofFn.goto use recursion onNat(rather than well-founded recursion). This resolves a problem reported on zulip). -
#8513 removes the
@[reducible]annotation onArray.size. This is probably best gone anyway in order to keep separation between theListandArrayAPIs, but it also helps avoid uselessly instantiatingArraytheorems whengrindis working onListproblems. -
#8515 removes the prime from
Fin.ofNat': the oldFin.ofNathas completed its 6 month deprecation cycle and is being removed. -
#8527 adds
grindannotations for theorems aboutList.countPandList.count. -
#8552 provides array iterators (
Array.iter(M),Array.iterFromIdx(M)), infinite iterators produced by a step function (Iter.repeat), and aForMinstance for finite iterators that is implemented in terms ofForIn. -
#8620 removes the
NatCast (Fin n)global instance (both the direct instance, and the indirect one viaLean.Grind.Semiring), as that instance causes causesx < n(forx : Fin k,n : Nat) to be elaborated asx < ↑nrather than↑x < n, which is undesirable. Note however that in Mathlib this happens anyway!
Compiler
-
#8211 adds support for generating IR from the LCNF representation of the new compiler.
-
#8236 fixes an issue where the combination of
extern_libandprecompileModuleswould lead to "symbol not found" errors. -
#8268 optimizes lean_nat_shiftr for scalar operands. The new compiler converts Nat divisions into right shifts, so this now shows up as hot in some profiles.
-
#8308 makes the new compiler's specialization pass compute closures the same way as the old compiler, in particular when it comes to variables captured by lambdas.
-
#8367 adds a new
structProjCasespass to the new compiler, analogous to thestruct_cases_onpass in the old compiler, which converts all projections from structs intocasesexpressions. When lowered to IR, this causes all of the projections from a single structure to be grouped together, which is an invariant relied upon by the IR RC passes (at least for linearity, if not general correctness). -
#8409 adds support to LCNF for native UInt8/UInt16/UInt32/UInt64 literals.
-
#8456 adds support for primitive USize literals in LCNF.
-
#8458 adds closed term extraction to the new compiler, closely following the approach in the old compiler. In the future, we will explore some ideas to improve upon this approach.
-
#8462 enables the LCNF extractClosed pass by default.
-
#8468 switches the LCNF baseExt/monoExt environment extensions to use a custom environment extension that uses a PersistentHashMap. The optimizer relies upon the ability to update a decl multiple times, which does not work with SimplePersistentEnvExtension.
-
#8502 changes the new compiler to use the kernel environment to find definitions, which causes compilation to be skipped when the decl had a kernel error (e.g. due to an unresolved metavariable). This matches the behavior of the old compiler.
-
#8521 makes LCNF.toMono recursively process jmp args.
-
#8523 moves the new compiler's noncomputable check into toMono, matching the recent change in the old compiler. This is mildly more complicated because we can't throw an error at the mere use of a constant, we need to check for a later relevant use. This is still a bit more conservative than it could theoretically be around join points and local functions, but it's hard to imagine that mattering in practice (and we can easily enable it if it does).
-
#8535 extracts more Nats (and their downstream users) in extractClosed by fixing a silly oversight in the logic.
-
#8540 changes the LCNF specialize pass to allow ground variables to depend on local fun decls (with no non-ground free variables). This enables specialization of Monad instances that depend on local lambdas.
-
#8559 fixes an adversarial soundness attack described in #8554. The attack exploits the fact that
assert!no longer aborts execution, and that users can redirect error messages. Another PR will implement the same fix forExpr.Data. -
#8560 is similar to #8559 but for
Expr.mkData. This vulnerability has not been exploited yet, but adversarial users may find a way. -
#8561 increases maxHeartbeats in the isDefEqProjIssue test, because when running under the new compiler the
run_metacall includes the allocations of the compiler itself. With the old compiler, many of the corresponding allocations were internal to C++ code and would not increase the heartbeat count. -
#8565 makes the LCNF specialization pass only treat type/instance params as ground vars. The current policy was too liberal and would result on computations being floated into specialized loops.
-
#8566 changes the LCNF constant folding pass to not convert Nat multiplication to a left shift by a power of 2. The fast path test for this is sufficiently complex that it's simpler to just use the fast path for multiplication.
-
#8575 makes LCNF's simpAppApp? bail out on trivial aliases as intended. It seems that there was a typo in the original logic, and this PR also extends it to include aliases of global constants rather than just local vars.
-
#8582 fixes an accidental dropping of state in Param.toMono. When this code was originally written, there was no other state besides
typeParams.
Pretty Printing
-
#8041 changes the behavior of
pp.showLetValuesto use a hoverable⋯to hide let values. This is now false by default, and there is a new optionpp.showLetValues.thresholdfor allowing small expressions to be shown anyway. For tactic metavariables, there is an additional optionpp.showLetValues.tactic.threshold, which by default is set to the maximal value, since in tactic states local values are usually significant. -
#8372 modifies the pretty printer to use
havesyntax instead oflet_funsyntax. -
#8457 fixes an issue when including a hard line break in a
Formatthat caused subsequent (ordinary) line breaks to be erroneously flattened to spaces. -
#8504 modifies the pretty printer so that dot notation is used for class parent projections. Previously, dot notation was never used for classes.
Documentation
-
#8199 adds a style guide for documentation, including both general principles and docstring-specific concerns.
Server
-
#7665 and #8180 add support for code actions that resolve 'Unknown identifier' errors by either importing the missing declaration or by changing the identifier to one from the environment.
-
#8091 improves the performance of the workspace symbol request.
-
#8242 fixes the 'goals accomplished' diagnostics. They were accidentally broken in #7902.
-
#8350 changes namespace completion to use the same algorithm as declaration identifier completion, which makes it use the short name (last name component) for completions instead of the full name, avoiding namespace duplications.
-
#8362 fixes a bug where the Unknown identifier code actions wouldn't work correctly for some Unknown identifier error spans and adjusts several Unknown identifier spans to actually end on the identifier in question.
Lake
-
#8383 fixes the use of
import Lakewith precompiled modules, which was previously broken on MacOS. -
#8411 fixes a doc bug in the Resolve.lean; in reverse order, B comes before A
-
#8528 fixes the heuristic Lake uses to determine whether a
lean_libcan be loaded vialean --pluginrather thanlean --load-dynlib. Previously, a mismatch between the single root's name and the library's name would not be caught and cause loading to fail. -
#8529 changes
lake leanandlake setup-fileto precompile the imports of non-workspace files using the the import's whole library. This ensures that additional link objects are linked and available during elaboration. -
#8539 changes Lake to use relative path for the Lean messages produced by a module build. This makes the message portable across different machines, which is useful for Mathlib's cache.