Compare commits

...

1036 Commits

Author SHA1 Message Date
Kim Morrison
d11293a731 feat: maximum?_eq_some_iff' 2024-06-24 21:44:42 +10:00
Leonardo de Moura
e3578c2f36 fix: discrepancy theorem vs example (#4493)
When the type of an `example` is a proposition,
we should elaborate on them as we elaborate on theorems.
This is particularly important for examples that are often
used in educational material.

Recall that when elaborating theorem headers, we convert unassigned
universe metavariables into universe parameters. The motivation is
that the proof of a theorem should not influence its statement.
However, before this commit, this was not the case for examples when
their type was a proposition.
This discrepancy often confused users.

Additionally, we considered extending the above behavior to definitions
when
1- When their type is a proposition. However, it still caused disruption
in Mathlib.
2- When their type is provided. That is, we would keep the current
behavior only if `: <type>` was omitted. This would make the elaborator
for `def` much closer to the one for `theorem`, but it proved to be too
restrictive.
For example, the following instance in `Core.lean` would fail:
```
instance {α : Sort u} [Setoid α] : HasEquiv α :=
  ⟨Setoid.r⟩
```
and we would have to write instead:
```
instance {α : Sort u} [Setoid α] : HasEquiv.{u, 0} α :=
  ⟨Setoid.r⟩
```
There are other failures like this in the core, and we assume many more
in Mathlib.

closes #4398
closes #4482 Remark: PR #4482 implements option 1 above. We may consider
it again in the future.
2024-06-24 01:18:41 +00:00
Kim Morrison
0f416c6a83 chore: mark releases as prerelease (#4544) 2024-06-24 01:04:04 +00:00
Markus Schmaus
5178c4b6da feat: change succ to + 1 (#4532)
The simp normal form of `succ` is `+ 1`, this changes additional
theorems to use that normal form.
2024-06-24 00:38:22 +00:00
Siddharth
bc6188a70a feat: BitVec.twoPow and lemmas, toward bitblasting multiplication for LeanSAT (#4417)
We add a new definition `BitVec.twoPow w i` to represent `(1#w <<< i)`.
This expression is used to test bits when building the multiplication
bitblaster.

Patch 1/?, being peeled from https://github.com/opencompl/lean4/pull/6.

---------

Co-authored-by: Tobias Grosser <github@grosser.es>
2024-06-23 22:37:02 +00:00
Leonardo de Moura
33f7865bbb fix: cached results at synthInstance? (#4530)
Synthesized type class instances may introduce new metavariables, and we
should actually cache `AbstractMVarsResult`.

closes #2283
2024-06-23 17:54:35 +00:00
Lean stage0 autoupdater
968aff403b chore: update stage0 2024-06-23 10:09:59 +00:00
Joachim Breitner
1076ca1ead chore: unset parseQuotWithCurrentStage in stage1’s src/stdlib_flags.h (#4537) 2024-06-23 09:44:14 +00:00
Bhavik Mehta
43a9c73556 chore: fix typo and incorrect name in doc (#4404)
Fixes typo "reflexivitiy" to "reflexivity", and changes exact Eq.rfl to
exact rfl, since Eq.rfl does not exist.

(I got something confused wrt the bot message on #4367 and accidentally
closed that one, so making this one instead, which I think satisfies the
requirements it wanted.)

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2024-06-23 09:06:50 +00:00
Kim Morrison
a92e9c7944 chore: move @[simp] from pred_le to sub_one_le (#4522)
(We already have a simp lemma unfolding `pred` to `· - 1`.)

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2024-06-23 07:58:38 +00:00
Joachim Breitner
378b02921d refactor: port recOn construction to Lean (#4516)
this is the simplest of the constructions to be ported from C++ to Lean,
so I’ll PR this one first.

This begins to put each construction into its own file, as it was the
case with C++.

For validation I developed this in a separate repository at
https://github.com/nomeata/lean-constructions/tree/fad715e
and checked that all `.recOn` declarations found in Lean and Mathlib are
identical (per `==`) to the ones produced by the C code.
2024-06-23 07:36:27 +00:00
Bolton Bailey
5426a5c8b3 chore: Remove simp from Option.elim, replace with individal simp lemmas (#4504)
This PR removes the `simp` attribute from `Option.elim` and adds it to
two related simp lemmas, `Option.elim_none` and `Option.elim_some`.

This PR comes from some discussion
[here](https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/optionEquivLeft_apply.20simp/near/438321459)
about `simps!` feeling too aggressive in unfolding this lemma.
2024-06-23 00:58:25 +00:00
Kim Morrison
d7da45cbe6 chore: fix explicitness of Prod.map lemmas (#4533) 2024-06-22 11:05:19 +00:00
Mac Malone
24d51b90cc fix: lake: remove module dynlib from platform-independent trace (#4478)
Fixes a bug where Lake incorrectly included the module dynlib in a
platform-independent trace. It was incorrectly excluded only external
native libraries from the trace. Also adds a test.
2024-06-22 01:24:23 +00:00
Mac Malone
0d529e18a6 feat: expose flags for the bundled C compiler (#4477)
Expose the C compiler and linker flags used with the bundled compiler
(clang) to Lean code. This is needed to skip the use of `leanc` in Lake.
2024-06-22 01:23:33 +00:00
Sebastian Ullrich
4808eb7c4b chore: Nix: fix cacheRoots 2024-06-21 23:35:38 +02:00
Sebastian Ullrich
5767a597d4 chore: update stage0 2024-06-21 22:04:02 +02:00
Sebastian Ullrich
e665a0d716 chore: Nix: fix update-stage0 2024-06-21 22:02:10 +02:00
Joachim Breitner
073b2cfc83 fix: cdot parser error message range (#4528)
as #4527 describes there is inconsistency between `by`, `case` and
`next` on the one hand who, if the goal isn’t closed, put squiggly
underlines on the first line, and `.`, which so far only squiggled the
dot (which is a very short symbol!)

With this change the same mechanism as used by `case`, namely
`withCaseRef`, is also used for `.`.

There is an argument for the status quo: The `.` tactic is more commonly
used
with further tactics on the same line, and thus there is now a higher
risk that
the user might think that the first tactic is broken. But 

* the same argument does apply to `by` and `case` where there was an
intentional
  choice to do it this way
* consistency and
* a squiggly line just under the short `.` is easy to miss, so it is
actually
better to underlining more here (at least until we have a better way to
  indicate incomplete proofs, which I have hopes for)

Fixes #4527, at least most of it.
2024-06-21 15:06:07 +00:00
David Thrane Christiansen
84e46162b5 feat: more infrastructure for tactic documentation (#4490)
This is the groundwork for a tactic index in generated documentation, as
there was in Lean 3. There are a few challenges to getting this to work
well in Lean 4:
* There's no natural notion of *tactic identity* - a tactic may be
specified by multiple syntax rules (e.g. the pattern-matching version of
`intro` is specified apart from the default version, but both are the
same from a user perspective)
* There's no natural notion of *tactic name* - here, we take the
pragmatic choice of using the first keyword atom in the tactic's syntax
specification, but this may need to be overridable someday.
* Tactics are extensible, but we don't want to allow arbitrary imports
to clobber existing tactic docstrings, which could become unpredictable
in practice.

For tactic identity, this PR introduces the notion of a *tactic
alternative*, which is a `syntax` specification that is really "the same
as" an existing tactic, but needs to be separate for technical reasons.
This provides a notion of tactic identity, which we can use as the basis
of a tactic index in generated documentation. Alternative forms of
tactics are specified using a new `@[tactic_alt IDENT]` attribute,
applied to the new tactic syntax. It is an error to declare a tactic
syntax rule to be an alternative of another one that is itself an
alternative. Documentation hovers now take alternatives into account,
and display the docs for the canonical name.

*Tactic tags*, created with the `register_tactic_tag` command, specify
tags that may be applied to tactics. This is intended to be used by
doc-gen and Verso. Tags may be applied using the `@[tactic_tag TAG1 TAG2
...]` attribute on a canonical tactic parser, which may be used in any
module to facilitate downstream projects introducing tags that apply to
pre-existing tactics. Tags may not be removed, but it's fine to
redundantly add them. The collection of tags, and the tactics to which
they're applied, can be seen using the `#print tactic tags` command.

*Extension documentation* provides a structured way to document
extensions to tactics. The resulting documentation is gathered into a
bulleted list at the bottom of the tactic's docstring. Extensions are
added using the `tactic_extension TAC` command. This can be used when
adding new interpretations of a tactic via `macro_rules`, when extending
some table or search index used by the tactic, or in any other way. It
is a command to facilitate its flexible use with various extension
mechanisms.
2024-06-21 12:49:30 +00:00
Kim Morrison
a1a245df40 chore: missing Prod.map lemmas (#4526) 2024-06-21 11:53:50 +00:00
Kim Morrison
07ee719761 chore: fix statement of List.filter_congr (#4525) 2024-06-21 11:36:07 +00:00
Kim Morrison
ee9996ec89 chore: fix statement of List.filter_congr (#4524) 2024-06-21 11:35:43 +00:00
Markus Schmaus
d2ae678fbf feat: change List.length_cons to use + 1 instead of succ (#4500)
The simp normal form of `succ` is `+ 1`, this changes `List.length_cons`
to use that normal form.
2024-06-21 11:25:07 +00:00
David Thrane Christiansen
2a00d6cf70 doc: more detailed docstring for PersistentEnvExtension (#4501)
Describes the intended modes of use, potential performance tradeoffs,
and data representation in more detail.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
Co-authored-by: Mac Malone <tydeu@hatpress.net>
2024-06-21 08:34:04 +00:00
Sebastian Ullrich
d020a9c5a6 feat: introduce Std (#4499)
Situated between `Init` and `Lean`, provides functionality not in the
prelude to both Lean's implementation and external users
2024-06-21 07:08:45 +00:00
Kim Morrison
301a89aba4 feat: lemmas about List.map (#4521) 2024-06-21 06:40:30 +00:00
Mac Malone
f32780d863 refactor: lake: more robust trace reading (#4518)
The recent change of the trace format exposed some unexpected issues
with Lake's tracing handling. This aims to fix that.

Lake will now perform a rebuild if the trace file is invalid/unreadable.
However, it will still fall back to modification times if the trace file
is missing. Also, Lake is now backwards compatible with the previous
pure numeric traces (and tolerates the absence of a `log` field in the
JSON trace).
2024-06-21 01:43:05 +00:00
Sebastian Ullrich
d6eab393f4 chore: fix benchmark 2024-06-20 18:18:41 +02:00
Sebastian Ullrich
1f732bb3b7 fix: missing unboxing in interpreter when loading initialized value (#4512)
Fixes #4457
2024-06-20 10:06:24 +00:00
Joe Hendrix
7d7f378e02 feat: complete Int div/mod simprocs (#3850)
This PR introduces complete simprocs for all the Int versions of
div/mod, and makes some small refactoring of Int lemmas and
library_search.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2024-06-20 04:42:31 +00:00
Kim Morrison
95db616cb6 chore: cherry-pick stray test from #3850 (#4509)
#3850 included a commit that added an extra test for `exact?`, but was
otherwise unrelated the to PR. It also removed a test. I've
cherry-picked that test over, and restored the deleted test, and next
will remove the commit from #3850.
2024-06-20 01:00:45 +00:00
Leonardo de Moura
45c5d009d6 fix: dsimp missing theorems for literals (#4467) 2024-06-20 00:35:53 +00:00
Leonardo de Moura
458835360f fix: [implemented_by] at functions defined by well-founded recursion (#4508)
closes #2899
2024-06-20 00:06:38 +00:00
Leonardo de Moura
3e05b0641b chore: fix test 2024-06-20 01:05:52 +02:00
Leonardo de Moura
53be53f5ae chore: update stage0 2024-06-20 01:05:52 +02:00
Leonardo de Moura
dac1dacc5b feat: add Rewrite.Config.newGoals field
It is not used yet. We need a update-stage0.
2024-06-20 01:05:52 +02:00
Leonardo de Moura
d3a7569c97 refactor: move ApplyNewGoals and ApplyConfig to Init 2024-06-20 01:05:52 +02:00
Leonardo de Moura
49f058cb76 feat: open _root_.<namespace> (#4505)
closes #3045
2024-06-19 21:59:46 +00:00
Joachim Breitner
bc047b8530 refactor: port mk_definition_inferring_unsafe to Lean (#4498)
this already can be used in two places, and will be used more as I port
more constructions. Hope the location in `Lean.Environment` is ok.
2024-06-19 18:26:19 +00:00
JovanGerb
c7c50a8bec chore: fix linter errors (#4502)
The linters in Batteries can be used to spot mistakes in Lean. See the
message on
[Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Go-to-def.20on.20typeclass.20fields.20and.20type-dependent.20notation/near/442613564).
These are the different linters with errors:

- unusedArguments:
There are many unused instance arguments, especially a redundant `[Monad
m]` is very common
- checkUnivs:
There was a problem with universes in a definition in
`Init.Control.StateCps`. I fixed it by adding a `variable` statement for
the implicit arguments in the file.
- defLemma:
many proofs are written as `def` instead of `theorem`, most notably
`rfl`. Because `rfl` is used as a match pattern, it must be a def. Is
this desirable?
The keyword `abbrev` is sometimes used for an alias of a theorem, which
also results in a def. I would want to replace it with the `alias`
keyword to fix this, but it isn't available.
- dupNamespace:
I fixed some of these, but left `Tactic.Tactic` and `Parser.Parser` as
they are as these seem intended.
- unusedHaveSuffices:
  I cleaned up a few proofs with unused `have` or `suffices`
- explicitVarsOfIff:
  I didn't fix any of these, because that would be a breaking change.
- simpNF:
I didn't fix any of these, because I think that requires knowing the
intended simplification order.
2024-06-19 18:24:08 +00:00
Leonardo de Moura
de269060d1 chore: fix tests 2024-06-19 20:21:34 +02:00
Leonardo de Moura
e8f768f9fd chore: cleanup PersistentHashMap.lean 2024-06-19 20:21:34 +02:00
Leonardo de Moura
0783d0fcbe chore: re-enable #reduce elaborator 2024-06-19 20:21:34 +02:00
Leonardo de Moura
2518105bd9 chore: update stage0 2024-06-19 20:21:34 +02:00
Leonardo de Moura
9096d6fc71 fix: remove PersistentHashMap.size
It is buggy and was unnecessary overhead.

closes #3029
2024-06-19 20:21:34 +02:00
Mario Carneiro
0a1a855ba8 fix: validate UTF-8 at C++ -> Lean boundary (#3963)
Continuation of #3958. To ensure that lean code is able to uphold the
invariant that `String`s are valid UTF-8 (which is assumed by the lean
model), we have to make sure that no lean objects are created with
invalid UTF-8. #3958 covers the case of lean code creating strings via
`fromUTF8Unchecked`, but there are still many cases where C++ code
constructs strings from a `const char *` or `std::string` with unclear
UTF-8 status.

To address this and minimize accidental missed validation, the
`(lean_)mk_string` function is modified to validate UTF-8. The original
function is renamed to `mk_string_unchecked`, with several other
variants depending on whether we know the string is UTF-8 or ASCII and
whether we have the length and/or utf8 char count on hand. I reviewed
every function which leads to `mk_string` or its variants in the C code,
and used the appropriate validation function, defaulting to `mk_string`
if the provenance is unclear.

This PR adds no new error handling paths, meaning that incorrect UTF-8
will still produce incorrect results in e.g. IO functions, they are just
not causing unsound behavior anymore. A subsequent PR will handle adding
better error reporting for bad UTF-8.
2024-06-19 14:05:48 +00:00
Joachim Breitner
c4718a87ab refactor: constructions: modify environment in lean world (#4474)
this is a first step towards porting the code `constructions.cpp` to
Lean: It leaves the construction of the `Declaration` untouched, but
moves adding the declarations to the environment, and setting various
attributes, to the Lean world.

This allows the remaining logic (the construction of the `Declaration`)
to be implemented in Lean separately and easily compared to the C++
implementation, before we replace that too.

To that end, `Declaraion` gains an `BEq` instance.

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
Co-authored-by: Arthur Adjedj <arthur.adjedj@ens-paris-saclay.fr>
2024-06-19 08:58:53 +00:00
Leonardo de Moura
357b52928f fix: global definition shadowing a local one when using dot-notation (#4497)
closes #3079
2024-06-19 05:52:45 +00:00
Mac Malone
bd45c0cd04 fix: lake: visit direct deps before adding manifest entries (#4485)
Fixes a bug in #4371 where the version of a package used by a dependency
would take precedence over that of a the same package as a direct
dependency if that package had a a manifest. This was because the direct
dependency's manifest entries were added before all the direct
dependencies were visited.
2024-06-19 02:49:59 +00:00
Mac Malone
f9952e8c39 refactor: touchup require syntax & docs (#4496)
A set of general tweaks of the `require` syntax and docs that provide a
base for #4495.

The sole significant behavioral change is that the `name` field of a
`require` in TOML now falls back to being interpreted as a simple string
name if the value is not a valid Lean identifier. This means that a
require for a package like `doc-gen4` can be written without French
quotes.
2024-06-19 02:49:57 +00:00
Kyle Miller
1b5b91cccf doc: add docstrings for dsimp configuration (#4258)
The dsimp configuration is a subset of the simp configuration, and so
it's a matter of copying the docstrings.
2024-06-19 00:05:25 +00:00
JovanGerb
74f1373706 chore: remove redundant if-else in isDefEqQuickOther (#4388)
I removed a redundant `if tFn.isMVar || sFn.isMVar then ... else return
LBool.undef` in the `else` clause of
```
if !tFn.isMVar && !sFn.isMVar then
  return LBool.undef
else
```
2024-06-18 23:44:29 +00:00
JovanGerb
c87205bc9b fix: eta reduce mvar assignments in isDefEq (#4387)
I made a modification to the `mkLambdaFVars` function, adding a
`etaReduce : Bool` parameter that determines whether a new lambda of the
form `fun x => f x` should be replaced by `f`. I then set this option to
true at `isDefEq` when processing metavariable assignments.

This means that many unnecessary eta unreduced expression are now
reduced. This is beneficial for users, so that they do not have to deal
with such unreduced expressions. It is also beneficial for performance,
leading to a 0.6% improvement in build instructions. Most notably,
`Mathlib.Algebra.DirectLimit`, previously a top 50 slowest file, has
sped up by 40%.

Quite a number of proof in mathlib broke. Many of these involve removing
a now unnecessary `simp only`. In other cases, a simp or rewrite doesn't
work anymore, such as a `simp_rw [mul_comm]` that was used to rewrite
`fun x => 2*x`, but now this term has turned into `HMul.hMul 2`.

Closes #4386
2024-06-18 23:41:40 +00:00
Leonardo de Moura
294b1d5839 chore: cleanup (#4494)
closes #4287
closes #4288
2024-06-18 23:39:16 +00:00
Leonardo de Moura
167771923e test: for isDefEq issue (#4492)
The issue has already been fixed in previous PRs.

closes #2461
2024-06-18 17:54:55 +00:00
Sebastian Ullrich
eb67654ae6 feat: incremental next and tactic if (#4459) 2024-06-18 12:36:59 +00:00
Joachim Breitner
6a8cb7ffa0 chore: nix shell: add gdb (#4476)
seems to work better when it comes from the same nixpkgs that we use for
building, it seems. And is plain convenient.
2024-06-18 11:07:20 +00:00
Kim Morrison
face4cef75 feat: complete API for List.replicate (#4487)
This is not the most exciting place to start, but I started here to:
* pick a function with little development in Batteries and Mathlib, so I
wouldn't have conflicts
* that is easy!
* to see how much effort it is to get fairly complete coverage
* and to set up some infrastructure to be used later, i.e.
`tests/lean/run/list_simp.lean`
2024-06-18 08:30:09 +00:00
Kim Morrison
6cad341764 chore: @[simp] List.getElem?_eq_getElem (#4488)
This is often helpful, and Mathlib doesn't mind.
2024-06-18 08:29:51 +00:00
Kim Morrison
2995e74133 chore: missing withSynthesize in #check_tactic (#4489)
Ran into this writing `#check_simp` tests for `List`. I guess it wasn't
a probably for `Bool` / `Prop`.
2024-06-18 05:24:45 +00:00
Kim Morrison
d768f46ba6 chore: @[simp] Nat.min_assoc (#4486) 2024-06-18 03:08:34 +00:00
Leonardo de Moura
97588301e1 fix: deprecated warning position at simp arguments (#4484)
closes #4452
2024-06-17 23:21:14 +00:00
Leonardo de Moura
fca87da2d4 fix: simp support for OfNat instances that are functions (#4481)
closes #4462
2024-06-17 22:01:25 +00:00
Leonardo de Moura
3c4d6ba864 feat: new #reduce elaborator
closes #4465
2024-06-17 23:27:34 +02:00
Leonardo de Moura
2c83e080f7 chore: update stage0 2024-06-17 23:27:34 +02:00
Leonardo de Moura
8f023b85c5 chore: move #reduce parser to Init/Notation.lean 2024-06-17 23:27:34 +02:00
Leonardo de Moura
06731f99d4 chore: missing instances (#4479)
cc @shigoel
2024-06-17 20:14:00 +00:00
Joachim Breitner
59a09fb4e7 feat: use priorities to ensure simp applies eqational lemmas in order (#4434)
This assigns priorities to the equational lemmas so that more specific
ones
are tried first before a possible catch-all with possible
side-conditions.

We assign very low priorities to match the simplifiers behavior when
unfolding
a definition, which happens in `simpLoop`’ `visitPreContinue` after
applying
rewrite rules.

Definitions with more than 100 equational theorems will use priority 1
for all
but the last (a heuristic, not perfect).

fixes #4173, to some extent.
2024-06-17 18:22:28 +00:00
Mac Malone
42c4a770c2 chore: lake: fix tests/init cleanup (#4468)
Forgot to update `tests/init/clean.sh` when I updated the test and
`.gitignore`.
2024-06-17 16:17:59 +00:00
Kim Morrison
d334e96275 chore: add forgotten deprecation (#4475) 2024-06-17 08:46:44 +00:00
Kim Morrison
e9caf40493 feat: cleanup @[simp] annotations for List (#4473)
These are mostly (sensible) `@[simp]` annotations that Mathlib adds.
2024-06-17 07:31:48 +00:00
Kim Morrison
a09726bb94 feat: lemmas about List.filter (#4472)
This upstreams some lemmas from Batteries, giving dumbed-down proofs, as
I do not (yet?) want to move up `List.Sublist`.
2024-06-17 06:53:16 +00:00
Markus Schmaus
1cf71e54cf feat: add missing theorems for + 1 and - 1 normal form (#4242)
`Nat.succ_eq_add_one` and `Nat.pred_eq_sub_one` are now simp lemmas. For
theorems about `Nat.succ` or `Nat.pred` without corresponding theorem
for `+ 1` or `- 1`, this adds the corresponding theorem.
2024-06-17 05:35:32 +00:00
Kim Morrison
2efcbfe803 feat: improvements to List.set and List.concat API (#4470) 2024-06-17 05:10:35 +00:00
Kim Morrison
03d01f4024 chore: reorganisation of List API (#4469)
This PR neither adds nor removes material, but improves the organization
of `Init/Data/List/*`.

These files are essentially completely re-ordered, to ensure that
material is developed in a consistent order between `List.Basic`,
`List.Impl`, `List.BasicAux`, and `List.Lemmas`.

Everything is organised in subsections, and I've added some module docs.
2024-06-17 04:21:53 +00:00
John Tristan
f237fb67eb doc: documenting Char and upstreaming extensionality from batteries (#4438)
* Basic documentation for characters
* Upstreamed two extensionality theorems from batteries

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2024-06-16 00:43:34 +00:00
Kim Morrison
e10a37d80d feat: switching List lookup normal forms to L[n] and L[n]? (#4400)
This is presumably going to have significant breakage downstream.
2024-06-15 07:35:36 +00:00
Joachim Breitner
fe0cb97c5d feat: use lazy MessageData for omega errors (#4360)
presumably this avoids unnecessary work when `omega` is used in tactic
combinators where the error message is never seen. Measurement did not
show
any significant changes, though.

With an artificial sleep in
```diff
diff --git a/src/Lean/Elab/Tactic/Omega/Frontend.lean b/src/Lean/Elab/Tactic/Omega/Frontend.lean
index fd297eef60..31ea3f6bd0 100644
--- a/src/Lean/Elab/Tactic/Omega/Frontend.lean
+++ b/src/Lean/Elab/Tactic/Omega/Frontend.lean
@@ -538,6 +538,7 @@ def formatErrorMessage (p : Problem) : OmegaM MessageData := do
     else
       let as ← atoms
       return .ofLazyM (es := as) do
+        IO.sleep 10000
         let mask ← mentioned as p.constraints
         let names ← varNames mask
         return m!"a possible counterexample may satisfy the constraints\n" ++
```
I can observe that `omega` is slow and `try omega` fast, so it seems to
work at least.
2024-06-14 20:21:37 +00:00
JovanGerb
c96797eb93 fix: show argument name in implicit argument error (#4426)
When an implicit argument cannot be inferred, the error should show the
name of the argument.

Showing the argument name in the error message for an uninstantiated
metavariable was introduced in da33f498f5,
but this implementation causes some argument names to get lost.
2024-06-14 18:08:42 +00:00
JovanGerb
4798c8418c perf: replace hasMVar by hasExprMVar in CollectMVars, FindMVar (#4451)
The modules `CollectMVars` and `FindMVars` only search for expression
metavariables and not level metavariables, so we should use
`Expr.hasExprMVar` instead of `Expr.hasMVar`.
2024-06-14 18:06:00 +00:00
David Thrane Christiansen
456ed44550 feat: add a linter for local vars that clash with their constructors (#4301)
This came up when watching new Lean users in a class situation. A number
of them were confused when they omitted a namespace on a constructor
name, and Lean treated the variable as a pattern that matches anything.

For example, this program is accepted but may not do what the user
thinks:
```
inductive Tree (α : Type) where
  | leaf
  | branch (left : Tree α) (val : α) (right : Tree α)

def depth : Tree α → Nat
  | leaf => 0
```
Adding a `branch` case to `depth` results in a confusing message.

With this linter, Lean marks `leaf` with:
```
Local variable 'leaf' resembles constructor 'Tree.leaf' - write '.leaf' (with a dot) or 'Tree.leaf' to use the constructor.
note: this linter can be disabled with `set_option linter.constructorNameAsVariable false`
```

Additionally, the error message that occurs when invalid names are
applied in patterns now suggests similar names. This means that:
```
def length (list : List α) : Nat :=
  match list with
  | nil => 0
  | cons x xs => length xs + 1
```
now results in the following warning on `nil`:
```
warning: Local variable 'nil' resembles constructor 'List.nil' - write '.nil' (with a dot) or 'List.nil' to use the constructor.
note: this linter can be disabled with `set_option linter.constructorNameAsVariable false`
```

and error on `cons`:
```
invalid pattern, constructor or constant marked with '[match_pattern]' expected

Suggestion: 'List.cons' is similar
```

The list of suggested constructors is generated before the type of the
pattern is known, so it's less accurate, but it truncates the list to
ten elements to avoid being overwhelming. This mostly comes up with
`mk`.
2024-06-14 13:03:09 +00:00
Sebastian Ullrich
237f392cc1 chore: update stage0 2024-06-14 12:35:45 +02:00
Sebastian Ullrich
5eb5fa49cf chore: Nix: fix update-stage0-commit 2024-06-14 12:35:14 +02:00
L
5d2403535a feat: default pp if pp expr/syntax/level without context (#4433)
This restores the behavior prior to
9f6bbfa106
for `MessageData.ofSyntax` `MessageData.ofExpr`, and
`MessageData.ofLevel` while staying within the new `.ofLazy` paradigm.

Also adds some documentation to help developers understand the missing
context issue.

Closes #4432

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2024-06-14 08:55:49 +00:00
Kim Morrison
2cf478cbbe chore: prefer · == a over a == · (#3056)
We recently discovered inconsistencies in Mathlib and Std over the
ordering of the arguments for `==`.

The most common usage puts the "more variable" term on the LHS, and the
"more constant" term on the RHS, however there are plenty of exceptions,
and they cause unnecessary pain when switching (particularly, sometimes
requiring otherwise unneeded `LawfulBEq` hypotheses).

This convention is consistent with the (obvious) preference for `x == 0`
over `0 == x` when one term is a literal.

We recently updated Std to use this convention
https://github.com/leanprover/std4/pull/430

This PR changes the two major places in Lean that use the opposite
convention, and adds a suggestion to the docstring for `BEq` about the
preferred convention.
2024-06-14 04:08:45 +00:00
Kim Morrison
b096e7d5f2 chore: make Name.isInternalDetail public, to remove duplication downstream (#4454)
This private function is duplicated downstream, so move it to the
`Lean.Name` namespace.
2024-06-14 01:55:52 +00:00
Mac Malone
1835dd123d feat: configuration DSL touchups (#4439)
This incorporates many general Lake DSL changes from #2439 and adds some
new related changes.

* Rework configuration names (e.g., `package <name>`)
  * String literals ca now be used instead of identifiers for names.
* The name syntax is now optional and can instead be set via the `name`
field.
* Avoid French quotes in `lake new` / `lake init` templates (except in
`lean_lib` names). This is not done for `lean_lib` because it needs a
proper identifier for its root. It could use a string and reparse it as
an identifier, but this seems liable to produce confusion.
* The `exe` templates now names it main module `Main` like the `std`
template.
* Improve `math` template error if `lean-toolchain` fails to download.
* Lake now logs a warning rather than an error on unknown configuration
fields. This increases the Lake DSL's cross-version compatibility.

Closes #3385.
2024-06-14 00:17:43 +00:00
Mac Malone
db74ee9e83 feat: lake: reliably cache logs and hashes (#4402)
Moves the cached log into the trace file (no more `.log.json`). This
means logs are no longer cached on fatal errors and this ensures that an
out-of-date log is not associated with an up-to-date trace. Separately,
`.hash` file generation was changed to be more reliable as well. `.hash`
files are deleted as part of the build and always regenerate with
`--rehash`.

Closes #2751.
2024-06-13 23:15:49 +00:00
Mac Malone
285a313078 chore: src/lake/lakefile.toml (#4446)
Use a TOML file for the Lake configuration of the `src/lake` directory
instead of a Lean file. This avoids having to load a version of the Lake
library to build Lake.
2024-06-13 16:56:32 +00:00
David Thrane Christiansen
8fef03d1cc feat: support Lake for building Lean core oleans (#3886)
This is from a ~~pair~~triple programming session with @tydeu and
@mhuisi.

If stage 1 is built with `-DUSE_LAKE=ON`, the CMake run will generate
`lakefile.toml` files for the root, `src`, and `tests`. These Lake
configuration files can then be used to build core oleans. While they do
not yet allow Lake to be used to build the Lean binaries. they do allow
Lake to be used for working interactively with the Lean source. In our
preliminary experiments, this allowed updates to `Init.Data.Nat` to be
noticed automatically when reloading downstream files, rather than
requiring a full manual compiler rebuild. This will make it easier to
work on the system.

As part of this change, Lake is added to stage 0. This allows Lake to
function in `src`, which uses the stage 0 toolchain.

---------

Co-authored-by: Mac Malone <tydeu@hatpress.net>
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-06-13 16:18:24 +00:00
Sebastian Ullrich
749bf9c279 fix: bad 'unknown package' error message (#4424)
This message is older than corresponding, better checks in Lake and
vscode-lean4

Fixes #4419

---------

Co-authored-by: Mac Malone <tydeu@hatpress.net>
2024-06-13 15:48:20 +00:00
Sebastian Ullrich
7b971b90c5 fix: redundant and wrong case in forEachModuleInDir (#4425)
Calling `f` on `dir.lean` for each `dir` is unnecessary as we call it on
each file anyway and the check was wrong because it ignored
`entry.root`.
2024-06-13 15:40:27 +00:00
Marc Huisinga
3119fd0240 fix: make watchdog more resilient against badly behaving clients (#4443)
This PR addresses some non-critical but annoying issues that sometimes
cause the language server to report an error:
- When using global search and replace in VS Code, the language client
sends `textDocument/didChange` notifications for documents that it never
told the server to open first. Instead of emitting an error and crashing
the language server when this occurs, we now instead ignore the
notification. Fixes #4435.
- When terminating the language server, VS Code sometimes still sends
request to the language server even after emitting a `shutdown` request.
The LSP spec explicitly forbids this, but instead of emitting an error
when this occurs, we now error requests and ignore all other messages
until receiving the final `exit` notification. Reported on Zulip several
times over the years but never materialized as an issue, e.g.
https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Got.20.60shutdown.60.20request.2C.20expected.20an.20.60exit.60.20notification/near/441914289.
- Some language clients attempt to reply to the file watcher
registration request before completing the LSP initialization dance. To
fix this, we now only send this request after the initialization dance
has completed. Fixes #3904.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-06-13 13:48:36 +00:00
Sebastian Ullrich
16cad2b45c chore: CI: do not fetch complete history 2024-06-13 14:50:49 +02:00
Sebastian Ullrich
6d265b42b1 chore: CI: fix github.event.pull_request.merge_commit_sha sometimes not being available 2024-06-13 14:47:42 +02:00
Sebastian Ullrich
c5120c1d0d chore: CI: fix Wasm release-ci (#4442) 2024-06-13 11:58:49 +00:00
Sebastian Ullrich
37f8b0390d chore: CI: fix workflow change breaking unrebased PRs (#4441) 2024-06-13 09:56:31 +00:00
Sebastian Ullrich
bd3b466f2f chore: CI: fix speedcenter tests (#4440) 2024-06-13 10:53:47 +02:00
Mac Malone
f3274d375a refactor: lake: simplify load code (#4371)
Simplifies the Lake dependency resolution code. Largely split from
#3998.
2024-06-13 03:22:47 +00:00
Sebastian Ullrich
a8de4b3b06 chore: CI: use Namespace runners (#4427) 2024-06-12 16:06:41 +00:00
Sebastian Ullrich
8d3be96024 fix: tactics in terms in tactics may break incremental reporting (#4436)
A pending tactic mvar managed to escape into an unexpected context in
specific circumstances.

```lean
example : True := by
  · rw [show 0 = 0 by rfl]
```
* Term elaboration of the `show` creates a pending mvar for the `by rfl`
proof
* `rw` fails with an exception because the pattern does not occur in the
target
* `cdot` catches the exception and admits the goal
* `Term.runTactic` [synthesizes all pending mvars from the tactic's
execution](5f9dedfe5e/src/Lean/Elab/SyntheticMVars.lean (L350)),
including the `by rfl` proof. But this would not have happened without
`cdot` as the exception would have skipped that invocation!
* Now incrementality is confused because the nested `by rfl` proof is
unexpectedly run in the same context as the top-level proof, writing to
the wrong promise, and the error message is lost

Solution: disable incrementality for these pending mvars
2024-06-12 14:59:24 +00:00
hwatheod
bedcbfcfee chore: fix typo in trace.split.failure error message (#4431)
should be "failure" not "failures"

Co-authored-by: q r <qr@abc.local>
2024-06-12 05:57:29 +00:00
Leonardo de Moura
ce6ebd1044 feat: dsimprocs for ite and dite (#4430) 2024-06-11 23:36:18 +00:00
Leonardo de Moura
ab73ac9d15 fix: missing simproc for BitVec equality (#4428) 2024-06-11 22:05:28 +00:00
Leonardo de Moura
3bd39ed8b6 perf: a isDefEq friendly Fin.sub (#4421)
The performance issue at #4413 is due to our `Fin.sub` definition.
```
def sub : Fin n → Fin n → Fin n
  | ⟨a, h⟩, ⟨b, _⟩ => ⟨(a + (n - b)) % n, mlt h⟩
```
Thus, the following runs out of stack space
```
example (a : UInt64) : a - 1 = a :=
  rfl
```
at the `isDefEq` test
```
(a.val.val + 18446744073709551615) % 18446744073709551616 =?= a.val.val
```

From the user's perspective, this timeout is unexpected since they are
using small numerals, and none of the other `Fin` basic operations (such
as `Fin.add` and `Fin.mul`) suffer from this problem.

This PR implements an inelegant solution for the performance issue. It
redefines `Fin.sub` as
```
def sub : Fin n → Fin n → Fin n
  | ⟨a, h⟩, ⟨b, _⟩ => ⟨((n - b) + a) % n, mlt h⟩
```
This approach is unattractive because it relies on the fact that
`Nat.add` is defined using recursion on the second argument.

The impact on this repo was small, but we want to evaluate the impact on
Mathlib.

closes #4413
2024-06-11 17:18:11 +00:00
Sebastian Ullrich
5f9dedfe5e chore: slightly more informative trace.Elab.snapshotTree 2024-06-11 10:44:04 +02:00
Kim Morrison
2a2b276ede chore: unify String.csize : Nat and Char.utf8Size : UInt32 as Char.size : Nat (#4357)
It seems:
* there was no actual need for the UInt32 valued version
* downstream we were getting duplicative lemmas about both
* so lets reduce the API surface area!

If anyone would prefer the remaining function is still called
`Char.utf8Size` I will happily change it. (`size` is hopefully still
unambiguous, and it's helpful to rename here so we can give a
deprecation warning that explains the type signature change.)

---------

Co-authored-by: Mac Malone <tydeu@hatpress.net>
2024-06-11 02:51:18 +00:00
Leonardo de Moura
ec775df6cc fix: rw should not include existing goal metavariables in the resulting subgoals (#4385)
closes #4381
2024-06-11 02:50:58 +00:00
Leonardo de Moura
c8e668a9ad fix: occurs check at metavariable types (#4420)
closes #4405
2024-06-11 00:16:19 +00:00
Leonardo de Moura
a1c8a941f0 fix: universe parameter order discrepancy between theorem and def (#4408)
Before this commit, the `theorem` and `def` declarations had different
universe parameter orders.
For example, the following `theorem`:
```
theorem f (a : α) (f : α → β) : f a = f a := by
  rfl
```
was elaborated as
```
theorem f.{u_2, u_1} : ∀ {α : Sort u_1} {β : Sort u_2} (a : α) (f : α → β), f a = f a :=
  fun {α} {β} a f => Eq.refl (f a)
```
However, if we declare `f` as a `def`, the expected order is produced.
```
def f.{u_1, u_2} : ∀ {α : Sort u_1} {β : Sort u_2} (a : α) (f : α → β), f a = f a :=
  fun {α} {β} a f => Eq.refl (f a)
```

This commit fixes this discrepancy.

@semorrison @jcommelin: This might be a disruptive change to Mathlib,
but it is better to fix the issue asap. I am surprised nobody has
complained about this issue before. I discovered it while trying to
reduce discrepancies between `theorem` and `def` elaboration.
2024-06-10 23:37:52 +00:00
L
6a7bed94d3 fix: kernel exception from fvars left from ?m a b instantiation (#4410)
Closes #4375

The following example raises `error: (kernel) declaration has free
variables '_example'`:
```lean
example: Nat → Nat :=
  let a : Nat := Nat.zero
  fun (_ : Nat) =>
    let b : Nat := Nat.zero
    (fun (_ : a = b) => 0) (Eq.refl a)
```

During elaboration of `0`, `elabNumLit` creates a synthetic mvar
`?_uniq.16` which gets abstracted by `elabFun` to `?_uniq.16 :=
?_uniq.50 _uniq.6 _uniq.12`. The `isDefEq` to `instOfNatNat 0` results
in:
```
?_uniq.50 :=
  fun (x._@.4375._hyg.13 : Nat) =>
    let b : Nat := Nat.zero
    fun (x._@.4375._hyg.23 : Eq.{1} Nat _uniq.4 b) =>
      instOfNatNat 0
```

This has a free variable `_uniq.4` which was `a`.

When the application of `?_uniq.50` to `#[#2, #0]` is instantiated, the
`let b : Nat := Nat.zero` blocks the beta-reduction and `_uniq.4`
remains in the expression.

fix: add `(useZeta := true)` here:

ea46bf2839/src/Lean/MetavarContext.lean (L567)
2024-06-10 19:02:27 +00:00
Henrik Böving
366f3ac272 feat: order the output of #print axioms (#4416)
Closes #4415
2024-06-10 09:17:05 +00:00
Sebastian Ullrich
ea46bf2839 fix: non-incremental command blocking further incremental reporting in macro (#4407)
As [reported on
Zulip](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/v4.2E9.2E0-rc1.20discussion/near/443356495).
2024-06-08 16:50:15 +00:00
Sebastian Ullrich
adfd438164 fix: incremental reuse leading to goals in front of the text cursor being shown (#4395)
As [reported on
Zulip](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/maybe.20a.20cache.20bug.3F).

We expected that for sound reuse of elaboration results, it is
sufficient to compare the old and new syntax tree's structure and atoms
including position info, but not the whitespace in between them.
However, we have at least one request handler, the goal view, that
inspects the whitespace after a tactic and thus could return incorrect
results on reuse. For now we implement the straightforward fix of
checking the whitespace as well. Alternatives like updating the
whitespace stored in the reused info tree are tbd.

This has the slight disadvantage that adding whitespace at the end of a
tactic will re-execute it (or the entire body, but not the header, if
the body is not a tactic block), but only up to typing the first
character of the next tactic or command.
2024-06-08 15:08:14 +00:00
Mac Malone
748eab9511 refactor: lake: inputBinFile / inputTextFile (#4384)
Deprecates `inputFile` and replaces it with `inputBinFile` and
`inputTextFile`. `inputTextFile` normalizes line endings, which helps
ensure text file traces are platform-independent.
2024-06-08 01:20:46 +00:00
Leonardo de Moura
fd4281a636 fix: misleading type at Option.forM (#4403)
The type uses `PUnit`, but the `pure ()` in the body was forcing the
implicit universe level at `PUnit` to be `1`.

We should probably elaborate `def`s like we elaborate theorems when the
resulting type is provided. This kind of mistake is hard to spot.
2024-06-07 23:33:15 +00:00
Markus Himmel
2d05ff8a48 perf: linearity in HashMap.(insert|erase) (#4372)
The speedcenter doesn't seem to care much, but in [my
benchmark](2e04b4f844/Hashmap/Benchmark/InsertReplace.lean)
for replace-heavy workloads, the fixed code is about 40% faster.
2024-06-07 22:41:39 +00:00
Leonardo de Moura
b02c1c56ab fix: improve split discriminant generalization strategy (#4401)
This commit also
- improves `split` error messages.
- adds `trace.split.failure` option.
- uses new convention for trace messages.

closes #4390
2024-06-07 21:35:09 +00:00
Kim Morrison
73348fb083 chore: make Array.reverse_data proof more robust (#4399)
This proof was breaking during a refactor, so making it more robust
first.
2024-06-07 19:17:03 +00:00
Henrik Böving
18264ae62e feat: getBitVecValue? understands BitVec.ofNatLt (#4391) 2024-06-07 17:43:08 +00:00
Sebastian Ullrich
7b72458392 chore: build Lake again 2024-06-07 13:59:22 +02:00
Sebastian Ullrich
bfcaaa3d9d chore: update stage0 2024-06-07 13:59:22 +02:00
Sebastian Ullrich
0768b508e6 chore: temporarily avoid building Lake 2024-06-07 13:59:22 +02:00
Sebastian Ullrich
d644b377bb chore: update stage0 2024-06-07 13:59:22 +02:00
Sebastian Ullrich
d85d3d5f3a fix: accidental ownership with specialization 2024-06-07 13:59:22 +02:00
Kim Morrison
745d77b068 chore: upstream @[simp] attribute (#4389)
Very minor, but progress towards deleting a downstream file.
2024-06-07 03:32:18 +00:00
Kyle Miller
63739a42f3 chore: clear releases_drafts for start of 4.10.0 (#4377) 2024-06-06 23:45:54 +00:00
Mac Malone
a99007ac75 perf: remove @[inline] from NameMap.find? (#4382)
This `@[inline]` causes Lean to respecialize `RBMap.find?` to `NameMap`
at each call site of `NameMap.find?`, creating lots of unnecessary
duplicate IR.
2024-06-06 22:53:14 +00:00
Henrik Böving
b9bfd30514 chore: remove partial TODO (#4380) 2024-06-06 18:04:55 +00:00
Leonardo de Moura
0a0f1d7cc7 fix: variable must execute pending tactics and elaboration problems (#4370)
closes #2226
closes #3214
2024-06-06 13:06:18 +00:00
Kim Morrison
ba97928fbf chore: begin development cycle for v4.10.0 (#4374) 2024-06-06 12:06:13 +00:00
Kim Morrison
287d46e1f6 chore: update stage0 2024-06-06 06:20:50 +01:00
Leonardo de Moura
0d30517dca feat: make <num>#<term> bitvector literal notation global
chore: `toFin_ofNat`
2024-06-06 06:20:50 +01:00
Leonardo de Moura
faea7f98c1 chore: missing registerTraceClass (#4369)
closes #3373
2024-06-06 00:53:16 +00:00
Leonardo de Moura
ff0d338dd2 feat: improve error messages for numerals (#4368)
closes #4365
2024-06-06 00:28:42 +00:00
Kim Morrison
56adfb856d chore: upstream basic String lemmas (#4354) 2024-06-05 21:28:43 +00:00
Mac Malone
9c079a42e1 chore: lake: add build log file path to warning (#4356)
Adds the path to build log to the warning for a missing/invalid build
log to help with debugging.
2024-06-05 15:18:08 +00:00
Sebastian Ullrich
9d47377bda feat: incrementality for careful command macros such as set_option in theorem, theorem foo.bar, lemma (#4364)
See Note [Incremental Macros] for the caveat on correct `withRef` use
2024-06-05 14:10:38 +00:00
Joachim Breitner
e33c32fb00 feat: ppOrigin to use MessageData.ofConst (#4362)
so that the pretty-printed origin is clickable, and avoid the
unnecessary `@`.

Particularly nice is this fix:
```diff
 /--
-info: [Meta.Tactic.simp.discharge] @bar discharge 
+info: [Meta.Tactic.simp.discharge] bar discharge 
       autoParam T _auto✝
-  [Meta.Tactic.simp.rewrite] { }:1000, T ==> True
-[Meta.Tactic.simp.rewrite] @bar:1000, U ==> True
+  [Meta.Tactic.simp.rewrite] T.mk:1000, T ==> True
+[Meta.Tactic.simp.rewrite] bar:1000, U ==> True
 -/
```
2024-06-05 11:00:34 +00:00
Joachim Breitner
42f12967a6 chore: CI: pr-release: install elan (#4361)
PR #4333 added a call to `lake`, but that needs elan installed
2024-06-05 08:20:57 +00:00
Joachim Breitner
5cd9f805b7 fix: without recover bad simp arg should fail (#4359)
this is an amendment to #4177, after @kmill pointed out an issue:

Users might expect that within a tactic combinator like `first`, `simp
[h]` fails if `h` does not exist. Therefore the behavior introduced in
PR #4177, which is really most useful in mormal interactive use of
`skip`, is restricted to when `recover := true`.
2024-06-05 08:05:38 +00:00
Joachim Breitner
f0a11b8864 fix: FunInd: support structural recursion on reflexive types (#4327)
types like
```
inductive Many (α : Type u) where
  | none : Many α
  | more : α → (Unit → Many α) → Many α
```
have a `.brecOn` only supports motives producing `Type u`, but not `Sort
u`, but our induction principles produce `Prop`. So the previous
implementation of functional induction would fail for functions that
structurally recurse over such types.

We recognize this case now and, rather hazardously, replace `.brecOn`
with `.binductionOn` (and thus `.below ` with `.ibelow` and `PProd` with
`And`). This assumes that these definitions are highly analogous.

This also improves the error message when realizing a reserved name
fails with an exception, by prepending
```
Failed to realize constant {id}:
```
to the error message.

Fixes #4320
2024-06-05 07:54:48 +00:00
Joachim Breitner
5a25612434 fix: GuessLex: delaborate unused parameters as _ (#4329)
fixes #4230
2024-06-05 07:54:29 +00:00
Kim Morrison
37d60fd2ec chore: use match_expr in omega (#4358) 2024-06-05 06:53:45 +00:00
Siddharth
fbb3055f82 feat: getLsb_signExtend (#4187)
The key idea is to notice that `signExtend` behavior is controlled by
the `msb`. When `msb = false`, `sext` behaves the same as `trunc`. When
`msb = true`, `sext` behaves like `trunc` but adds high 1-bits. This is
expressed using the negate-truncate-negate pattern. Lemma statements
below:

```lean
theorem signExtend_eq_neg_truncate_neg_of_msb_false {x : BitVec w} {v : Nat} (hmsb : x.msb = false) :
    (x.signExtend v) = x.truncate v := by
 
theorem signExtend_eq_neg_truncate_neg_of_msb_true {x : BitVec w} {v : Nat} (hmsb : x.msb = true) :
    (x.signExtend v) = ~~~((~~~x).truncate v) := by
```

These give the final theorem statement:


```lean
theorem getLsb_signExtend {x  : BitVec w} {v i : Nat} :
    (x.signExtend v).getLsb i = (decide (i < v) && if i < w then x.getLsb i else x.msb) := by
```

---------

Co-authored-by: Tobias Grosser <github@grosser.es>
Co-authored-by: Alex Keizer <alex@keizer.dev>
Co-authored-by: Kim Morrison <scott@tqft.net>
2024-06-05 05:17:29 +00:00
Austin Letson
644c1d4e36 doc: add docstrings and examples for String functions (#4332)
Add docstrings, usage examples, and doctests for `String.get'`,
`String.next'`, `String.posOf`, `String.revPosOf`.
2024-06-05 05:16:56 +00:00
Leonardo de Moura
46db59d1d9 fix: split (for if-expressions) should work on non-propositional goals (#4349)
Remark: when splitting an `if-then-else` term, the subgoals now have
tags `isTrue` and `isFalse` instead of `inl` and `inr`.
closes #4313

---------

Co-authored-by: Mario Carneiro <di.gama@gmail.com>
2024-06-05 04:43:46 +00:00
Leonardo de Moura
c53a350a9e chore: apply naming convention to IsLawfulSingleton (#4350)
closes #4324
2024-06-05 04:33:20 +00:00
Kim Morrison
8f507b1008 chore: simplify lean4checker step in release checklist (#4355) 2024-06-05 04:14:36 +00:00
Mac Malone
28b8778218 perf: lake: fix LogIO inling/lifting (#4351)
The current manner of lifting `LogIO` into `CliM` produces excessive
specializations (due to a nested inlined `forM`). There was also a bug
where `IO` was lifted into `CliM` via `LogIO` rather than directly
through `MainM`.
2024-06-05 01:59:21 +00:00
Leonardo de Moura
982c338b45 fix: missing dsimp simplification when applying auto-congr theorems (#4352)
closes #4339
2024-06-05 01:01:33 +00:00
Mac Malone
ce67d6ef9e fix: lake: track trace of cached build logs (#4343)
Stores the dependency trace for a build in the cached build log and then
verifies that it matches the trace of the current build before replaying
the log. Includes test.

Closes #4303.
2024-06-05 00:35:09 +00:00
Kim Morrison
1d6fe34b29 chore: upstream Char lemmas from Mathlib (#4348)
The main purpose here is to add `Char.ofUInt8`, so I can delete the
semantically suspect `UInt8.toLower` etc in Mathlib.
2024-06-04 23:45:26 +00:00
Leonardo de Moura
5924c5aea9 fix: simp must not use the forward version of an user-specified backward theorem (#4345)
closes #4290
2024-06-04 22:49:31 +00:00
Mac Malone
612bdee68c test: lake: more robust tests/serve (#4346)
In Lake's `tests/serve`, save server log to a file and give it a timeout
(one smaller than CMake's).
2024-06-04 22:38:20 +00:00
Leonardo de Moura
28cf1cf5cf fix: mutual inductives with instance parameters (#4342)
closes #4310
2024-06-04 17:35:41 +00:00
Leonardo de Moura
2ae762eb75 fix: panic when applying @[simp] to malformed theorem syntax (#4341)
closes #4309
2024-06-04 16:52:26 +00:00
Sebastian Ullrich
8437d1f660 fix: incorrect info tree reuse (#4340)
The `save` happened in a slightly different context from the restore,
which a refinement of the `saveOrRestoreFull` signature now makes
impossible.

Fixes #4328
2024-06-04 09:28:40 +00:00
Sebastian Ullrich
d45952e386 feat: incremental have (#4308)
Implemented as a macro special case, with some implementation caveats
2024-06-04 09:12:27 +00:00
Siddharth
9d46961236 chore: deprecate shiftLeft_shiftLeft, shiftRight_shiftRight (#4321)
As discussed previously
(https://github.com/leanprover/lean4/pull/4179#discussion_r1615183093),
we deprecate the two functions in favour of `shift{Left, Right}_add`.
2024-06-04 01:57:51 +00:00
Kyle Miller
e47d84e37a doc: improve docstrings for repeat* tactics (#4338) 2024-06-04 01:47:40 +00:00
Kim Morrison
05ea3ac19f chore: update batteries in manifest when creating lean-pr-testing-NNNN at Mathlib (#4333) 2024-06-04 01:45:37 +00:00
Kyle Miller
a54fa7cae6 fix: partial calc tactic would fail due to mdata or uninstantiated mvars (#4335)
Reported by Heather Macbeth.

Closes #4334

---------

Co-authored-by: Heather Macbeth <25316162+hrmacbeth@users.noreply.github.com>
2024-06-04 01:23:20 +00:00
Joachim Breitner
f65e3ae985 feat: simp to still work even if one simp arg does not work (#4177)
this fixes a usability paper cut that just annoyed me. When editing a
larger simp proof, I usually want to see the goal state after the simp,
and this is what I see while the `simp` command is complete. But then,
when I start typing, and necessarily type incomplete lemma names, that
error makes `simp` do nothing again and I see the original goal state.
In fact, if a prefix of the simp theorem name I am typing is a valid
identifier, it jumps even more around.

With this PR, using `logException`, I still get the red squiggly lines
for the unknown identifer, but `simp` just ignores that argument and
still shows me the final goal. Much nicer.

I also demoted the message for `[-foo]` when `foo` isn’t `simp` to a
warning and gave it the correct `ref`.

See it in action here: (in the middle, when you suddenly see the
terminal,
I am switching lean versions.)


https://github.com/leanprover/lean4/assets/148037/8cb3c563-1354-4c2d-bcee-26dfa1005ae0
2024-06-03 14:21:31 +00:00
Siddharth
81f5b07215 feat: getLsb_sshiftRight (#4179)
In the course of the development, I grabbed facts about right shifting
over integers [from
`mathlib4`](https://github.com/leanprover-community/mathlib4/blob/master/Mathlib/Data/Int/Bitwise.lean).

The core proof strategy is to perform a case analysis of the msb:
- If `msb = false`, then `sshiftRight = ushiftRight`.
- If `msb = true`. then `x >>>s i = ~~~(~~~(x >>>u i))`. The double
negation introduces the high `1` bits that one expects of the arithmetic
shift.

---------

Co-authored-by: Kim Morrison <scott@tqft.net>
2024-06-01 16:43:11 +00:00
Siddharth
9a597aeb2e feat: getLsb_{rotateLeft, rotateRight} (#4257)
These will be used by LeanSAT for bitblasting rotations by constant
distances.

We first reduce the case when the rotation amount is larger than the
width to the case where the rotation amount is less than the width
(`x.rotateLeft/Right r = x.rotateLeft/Right (r%w)`).

Then, we case analyze on the low bits versus the high bits of the
rotation, where we prove equality by extensionality.

---------

Co-authored-by: Alex Keizer <alex@keizer.dev>
Co-authored-by: Tobias Grosser <github@grosser.es>
2024-06-01 16:42:10 +00:00
Tobias Grosser
ff116dae5f feat: add BitVec _assoc lemmas (#4299) 2024-06-01 16:24:18 +00:00
John Tristan
0dff5701af doc: updated build instructions for mac os X (#4317)
Edit to the platform specific setup for mac os X. The installation of
llvm does not accept the options --with-clang and --with-asan anymore.
2024-06-01 16:23:17 +00:00
Kim Morrison
299cb9a806 chore: remove @[simp] from bind_eq_some (#4314) 2024-06-01 16:04:02 +00:00
Leonardo de Moura
b53a74d6fd fix: miscompilation in constant folding (#4311)
closes #4306
2024-05-31 04:24:45 +00:00
Lean stage0 autoupdater
007b423006 chore: update stage0 2024-05-30 09:57:02 +00:00
Sebastian Ullrich
6c63c9c716 feat: quotations for parser aliases (#4307)
Another papercut towards incremental `have`
2024-05-30 09:22:22 +00:00
Kim Morrison
8bbb015a97 chore: add namespace in Init/Data/Fin/Fold (#4304) 2024-05-29 16:40:55 +00:00
Alex Keizer
9133470243 feat: upstream BitVec.toFin_ofNat and BitVec.toFin_neg (#4298)
These lemmas are morally equivalent to Mathlib lemmas which are proposed
to be deleted from Mathlib in
[#13286](https://github.com/leanprover-community/mathlib4/pull/13286).

It is only morally equivalent, because the Mathlib lemmas are stated in
terms of Mathlib-defined things: `toFin_natCast` uses a coercion from
`Nat` to `Fin (2^w)` which relies on `NeZero` machinery available only
in Mathlib. Thus, I've rephrased the rhs in terms of the def-eq
`Fin.ofNat'` with an explicit proof that `2^w` is non-zero.

Similarly, the RHS of `toFin_neg` was phrased in terms of negation on
`Fin`s, which is only defined in Mathlib, so I've unfolded the
definition.
2024-05-29 08:25:51 +00:00
Markus Himmel
d07b316804 fix: incorrect docstring for named pattern syntax (#4294)
---
2024-05-29 08:23:15 +00:00
Wojciech Nawrocki
ec59e7a2c0 feat: widget messages (#4254)
Allows embedding user widgets in structured messages. Companion PR is
leanprover/vscode-lean4#449.

Some technical choices:
- The `MessageData.ofWidget` constructor might not be strictly necessary
as we already have `MessageData.ofFormatWithInfos`, and there is
`Info.ofUserWidget`. However, `.ofUserWidget` also requires a `Syntax`
object (as it is normally produced when widgets are saved at a piece of
syntax during elaboration) which we do not have in this case. More
generally, it continues to be a bit cursed that `Elab.Info` nodes are
used both for elaboration and delaboration (pretty-printing), so
entrenching that approach seems wrong. The better approach would be to
have a separate notion of pretty-printer annotation; but such a refactor
would not be clearly beneficial right now.
- To support non-JS-based environments such as
https://github.com/Julian/lean.nvim, `.ofWidget` requires also providing
another message which approximates the widget in a textual form.
However, in practice these environments might still want to support a
few specific user widgets such as "Try this".

---

Closes #2064.
2024-05-29 06:37:42 +00:00
Sebastian Ullrich
cc33c39cb0 chore: bootstrap fixes 2024-05-28 23:04:19 +02:00
Sebastian Ullrich
8c7364ee64 chore: update stage0 2024-05-28 23:04:19 +02:00
Sebastian Ullrich
26b6718422 chore: haveId node kind 2024-05-28 23:04:19 +02:00
Sebastian Ullrich
66777670e8 fix: stray tokens in tactic block should not inhibit incrementality (#4268) 2024-05-27 07:36:13 +00:00
Sebastian Ullrich
f05a82799a chore: CI: restore macOS aarch64 install sufix 2024-05-26 14:29:56 +02:00
Leonardo de Moura
8eee5ff27f fix: do not include internal match equational theorems at simp trace (#4274)
closes #4251
2024-05-25 17:16:19 +00:00
Mac Malone
fe17b82096 refactor: lake: ensure job actions can be lifted to FetchM (#4273)
In `v4.8.0-rc2`, due to additional build refactor changes, `JobM` no
longer cleanly lifts in `FetchM`. Generally, a `JobM` action should not
be run `FetchM` directly but spawned asynchronously as job (e.g., via
`Job.async`). However, there may be some edge cases were this is
necessary and it is a backwards compatibility break, so this change adds
back the lift. This change also includes an `example` definition to
ensure the lift works in order to prevent similar accidental breakages
in the future.

This breakage was first reported by Mario on
[Zulip](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/v4.2E8.2E0-rc2.20discussion/near/440407037).
2024-05-25 02:20:04 +00:00
Mac Malone
def00d3920 refactor: lake: manifest semver & code cleanup (#4083)
Switches the manifest format to use `major.minor.patch` semantic
versions. Major version increments indicate breaking changes (e.g., new
required fields and semantic changes to existing fields). Minor version
increments (after `0.x`) indicate backwards-compatible extensions (e.g.,
adding optional fields, removing fields). This change is backwards
compatible. Lake will still successfully read old manifest with numeric
versions. It will treat the numeric version `N` as semantic version
`0.N.0`. Lake will also accept manifest versions with `-` suffixes
(e.g., `x.y.z-foo`) and then ignore the suffix.

This change also includes the general cleanup/refactoring of the
manifest code and data structures that was part of #3174.
2024-05-24 21:32:41 +00:00
Mac Malone
cd16975946 feat: lake pack / lake unpack (#4270)
Adds two new Lake commands, `lake pack` and `lake unpack`, which pack
and unpack, respectively, Lake build artifacts from an archive. If a
path argument is given, creates the archive specified, otherwise uses
the information in a package's `buildArchive` configuration as the
default.

The pack command will be used by Reservoir to prepare crate-style build
archives for packages. In the future, the command will also be
extensible through configuration file hooks.
2024-05-24 21:32:07 +00:00
Mac Malone
0448e3f4ea feat: lake test improvements & lake lint (#4261)
Extends the functionality of `lake test` and adds a parallel command in
`lake lint`.

* Rename `@[test_runner]` / `testRunner` to `@[test_driver]` /
`testDriver`. The old names are kept as deprecated aliases.
* Extend help page for `lake test` and adds one for `lake check-test`. 
* Add `lake lint` and its parallel tag `@[lint_driver]` , setting
`lintDriver`, and checker `lake check-lint`.
* Add support for specifying test / lint drivers from dependencies. 
* Add `testDriverArgs` / `lintDriverArgs` for fixing additional
arguments to the invocation of a driver script or executable.
* Add support for library test drivers (but not library lint drivers). 
* `lake check-test` / `lake check-lint` only load the package (without
dependencies), not the whole workspace.

Closes #4116. Closes #4121. Closes #4142.
2024-05-24 21:31:41 +00:00
Sebastian Ullrich
d3ee0be908 feat: show signature elaboration errors on body parse error (#4267)
Fixes #3556

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2024-05-24 10:07:07 +00:00
Sebastian Ullrich
d1a96f6d8f chore: CI: native-compile aarch64 macOS (#4265) 2024-05-24 08:18:49 +00:00
Kim Morrison
b0c1112471 chore: better omega error message if no facts found (#4264) 2024-05-24 05:15:15 +00:00
JovanGerb
e5e5a4d2e0 chore: fix the MonadStore type classes, with semiOutParam (#4205)
The type class `MonadStore1` and friends have an outParam, which should
not be an outParam, because there are multiple possible values for this
parameter. At this function
[fetchOrCreate](1382e9fbc4/src/lake/Lake/Load/Main.lean (L196C49-L196C63)),
there are multiple stacked `StateT` monad transformers that each give a
different instance to `MonadStore1`. It is an implementation detail of
type class synthesis which instance is found. This particular type class
synthesis fails when the unused instance
`Lake.instMonadStore1OfMonadDStoreOfFamilyOut` is set to a lower
priority, because then the synthesis order happens to go differently, so
the wrong instance is found.

Replacing the outParam with a semiOutParam solves this issue. Thus, we
make a new type class `MonadStore1Of`, which is the same, but with a
semiOutParam. This follows the design of `MonadState` and
`MonadStateOf`.

However, then it turns out that the instance cannot anymore be
synthesised.

There are two instances for `MonadStore1`:
```
instance [MonadDStore κ β m] : MonadStore1 k (β k) m
instance [MonadDStore κ β m] [FamilyOut β k α] : MonadStore1 k α m 
```
The first one is problematic during unification, especially when `β`
should be instantiated as a constant function. We make the second one
sufficient by adding an instance for the general type family:
```
/-- The general type family -/
instance (priority := low) : FamilyDef Fam a (Fam a) where
  family_key_eq_type := rfl
```
So then we can get rid of the first instance.
2024-05-24 02:09:07 +00:00
Sebastian Ullrich
e020f3d159 chore: CI: move some expensive checks from merge queue to releases (#4255) 2024-05-23 20:45:44 +00:00
Sebastian Ullrich
811bad16e1 fix: ensure incremental commands and tactics are reached only on supported paths (#4259)
Without this, it would not easy but perhaps be feasible to break
incrementality when editing command prefixes such as `set_option ... in
theorem` or also `theorem namesp.name ...` (which is a macro),
especially if at some later point we support incrementality in input
shifted by an edit. Explicit, sound support for these common cases will
be brought back soon.
2024-05-23 17:57:42 +00:00
Sebastian Ullrich
67338bac23 chore: replace registerBuiltinIncrementalTactic with @[builtin_incremental] 2024-05-23 17:53:58 +02:00
Sebastian Ullrich
ba629545cc chore: update stage0 2024-05-23 17:26:21 +02:00
Sebastian Ullrich
dfb496a271 fix: allow multiple declareBuiltin per declaration 2024-05-23 17:23:39 +02:00
Sebastian Ullrich
250994166c feat: [(builtin_)incremental] elab attribute 2024-05-23 17:23:39 +02:00
Sebastian Ullrich
73a0c73c7c chore: modernize build instructions (#4032)
Use `cmake --preset`, adjust and document parallelism settings
2024-05-23 10:55:07 +00:00
meow-sister
258cc28dfc fix: docstring in Attributes.lean (#4238)
Changing document string in `Attributes.lean`, in order to consistent
with code in `Lean.Parser.Attr`.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2024-05-23 10:13:43 +00:00
Sebastian Ullrich
f61a64d2ff chore: reset LEAN_VERSION_IS_RELEASE 2024-05-23 12:28:24 +02:00
Kyle Miller
d984030c6a chore: set up procedure for preparing release notes (#4247)
We are switching to a new system for preparing release notes.
* Release notes will be compiled when creating a release candidate from
all the commits that are part of that release.
* PRs can include suggestions for release notes in PR messages. Please
use language such as "release notes" and "breaking changes" to call
attention to the suggestions. Release notes are user-centric rather than
developer-centric.
* For more complicated release notes, these can be put into the
`releases_drafts` folder.

This solves an issue where PRs that include release notes can, when
merged, have those notes appear under the wrong Lean version, since they
might have been created before a release but not merged until after. It
also solves merge conflicts due to multiple PRs updating the release
notes.
2024-05-23 02:46:11 +00:00
FR
93758cc222 perf: faster Nat.testBit (#4188)
`1 &&& n` is faster than `n &&& 1` for big `n`.

---
2024-05-23 01:34:40 +00:00
Alex Keizer
4fa3b3c4a0 feat: bitblasting theorems for signed comparisons (#4201)
Prove theorems that relate `BitVec.slt` and `sle` to `carry`, so that
these signed comparisons may be bitblasted in LeanSAT.

This PR is stacked on top of #4200. For the diff without changes from
that PR, see:
https://github.com/opencompl/lean4/compare/opencompl:lean4:bitvec-toInt-iff-msb...bitvec-slt-blast

---------

Co-authored-by: Kim Morrison <scott@tqft.net>
2024-05-23 01:24:04 +00:00
Leonardo de Moura
2bc41d8f3a fix: case tactic in macros (#4252)
We must erase macro scopes for tags in `case` as we do in `cases .. with
..` and `induction .. with ..`.
2024-05-23 00:01:24 +00:00
Sebastian Ullrich
f97a7d4234 feat: incremental elaboration of definition headers, bodies, and tactics (#3940)
Extends Lean's incremental reporting and reuse between commands into
various steps inside declarations:
* headers and bodies of each (mutual) definition/theorem
* `theorem ... := by` for each contained tactic step, including
recursively inside supported combinators currently consisting of
  * `·` (cdot), `case`, `next`
  * `induction`, `cases`
  * macros such as `next` unfolding to the above

![Recording 2024-05-10 at 11 07
32](https://github.com/leanprover/lean4/assets/109126/c9d67b6f-c131-4bc3-a0de-7d63eaf1bfc9)

*Incremental reuse* means not recomputing any such steps if they are not
affected by a document change. *Incremental reporting* includes the
parts seen in the recording above: the progress bar and messages. Other
language server features such as hover etc. are *not yet* supported
incrementally, i.e. they are shown only when the declaration has been
fully processed as before.

---------

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-05-22 13:23:30 +00:00
Alex Keizer
23a202b6be feat: characterize BitVec.toInt in terms of BitVec.msb (#4200)
This PR extracts `msb_eq_false_iff_two_mul_lt` and
`msb_eq_true_iff_two_mul_ge` from #4179, and uses them to prove a
theorem that characterizes `BitVec.toInt` in terms of `BitVec.msb`. This
lemma will be useful to prove a bit-blasting theorem for `BitVec.slt`
and `BitVec.sle`.

Also cleans up an existing proof (`toInt_eq_toNat_cond `), which turns
out to be provable by `rfl`.

---------

Co-authored-by: Kim Morrison <scott@tqft.net>
2024-05-22 11:14:37 +00:00
Leonardo de Moura
ff37e5d512 feat: add grind core module (#4249) 2024-05-22 03:50:36 +00:00
Kim Morrison
c2b8a1e618 chore: fix implicitness in HashMap.ofList (#4248)
Reported at
https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Typeclass.20Inference.20Failure.20on.20HashMap/near/439842209
2024-05-22 03:04:37 +00:00
Mac Malone
8ca00918fb chore: lake: fix noRelease test when lean repo is tagged (#4244)
Fixes a bug with the Lake `noRelease` test where the test would fail if
the current revision of the Lean repository itself had a tag.
2024-05-21 22:51:33 +00:00
Leonardo de Moura
6155513c60 chore: update stage0
Motivation: `[grind_cases]` at `Init`
2024-05-21 21:46:23 +02:00
Leonardo de Moura
d6709eb157 feat: add [grind_cases] attribute 2024-05-21 21:46:23 +02:00
Leonardo de Moura
e6be8b90f5 feat: add grind.injection (#4243) 2024-05-21 17:57:02 +00:00
Joachim Breitner
82401938cf fix: hovers on binders with metavariables (#4192)
this fixes #4078. It is an alternative fix to the one in #4137,
suggested
by @kmill.

Incidentially, it makes the unused variable linter better. My theory is
that
if we don’t reset the info when backtracking, the binder shows up more
than
once in the info tree, and then it is considered “used”, although there
are
just multiple binders.
2024-05-21 10:34:58 +00:00
Kim Morrison
3de60bb1f6 chore: Lake details & improve formatting in changelog (#4239)
This is #4207, but targeting `master`.

Co-authored-by: Mac Malone <tydeu@hatpress.net>
2024-05-21 06:11:32 +00:00
Leonardo de Moura
8c03650359 feat: some Char, UInt, and Fin theorems (#4231)
for SSFT24 summer school: https://github.com/david-christiansen/ssft24

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
Co-authored-by: Kim Morrison <scott.morrison@gmail.com>
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-05-21 06:11:23 +00:00
Austin Letson
2faa81d41f doc: add docstrings and examples for String functions (#4166)
Add docstrings, usage examples, and doc tests for `String.prev`,
`.front`, `.back`, `.atEnd`.

Improve docstring examples for `String.next` based on discussion
examples for `String.prev`.

---------

Co-authored-by: Kim Morrison <kim@tqft.net>
2024-05-21 04:27:40 +00:00
Siddharth
097a4d5b6b feat: define rotateLeft/Right with modulo (#4229)
This ensures that rotateLeft/Right behave correctly even when the
rotation amount is larger than the bitwidth.

This shall be followed up with `getLsb` theorems for rotations for
LeanSAT.

We choose to write `aux` definitions since it is cleaner to reason about
the `aux` theorems with the assumption that `rotation-amount <
bit-width`, followed by auxiliary lemmas that link the behavior of
rotation to the canonical case when `rotation-amount < bit-width`.

Proof strategy we will execute based on these definitions: [Link to
proof of
`getLsb_rotateLeft`](a0b18ec0f4/src/Init/Data/BitVec/Lemmas.lean (L1129-L1204))

---------

Co-authored-by: Tobias Grosser <github@grosser.es>
2024-05-21 03:49:09 +00:00
Mac Malone
f512826b9a chore: lake: spinner icon for computing step (#4236) 2024-05-21 03:48:39 +00:00
Leonardo de Moura
7c053259d3 feat: add grind.cases tactic (#4235) 2024-05-21 02:03:33 +00:00
Leonardo de Moura
f3ccd6b023 feat: some string simprocs (#4233)
For the SSFT24 summer school.
2024-05-20 22:53:10 +00:00
Mac Malone
7ece5d56e3 feat: lake: ANSI monitor: only display progress + running job info (#4232)
The ANSI mode build monitor now now longer displays built jobs (instead
only those that print info or failed). Also upgrades the progress ticker
with a spinner icon and information on the number of running jobs.
2024-05-20 20:29:21 +00:00
Kyle Miller
a7338c5ad8 feat: make frontend normalize line endings to LF (#3903)
To eliminate parsing differences between Windows and other platforms,
the frontend now normalizes all CRLF line endings to LF, like [in
Rust](https://github.com/rust-lang/rust/issues/62865).

Effects:
- This makes Lake hashes be faithful to what Lean sees (Lake already
normalizes line endings before computing hashes).
- Docstrings now have normalized line endings. In particular, this fixes
`#guard_msgs` failing multiline tests for Windows users using CRLF.
- Now strings don't have different lengths depending on the platform.
Before this PR, the following theorem is true for LF and false for CRLF
files.
```lean
example : "
".length = 1 := rfl
```

Note: the normalization will take `\r\r\n` and turn it into `\r\n`. In
the elaborator, we reject loose `\r`'s that appear in whitespace. Rust
instead takes the approach of making the normalization routine fail.
They do this so that there's no downstream confusion about any `\r\n`
that appears.

Implementation note: the LSP maintains its own copy of a source file
that it updates when edit operations are applied. We are assuming that
edit operations never split or join CRLFs. If this assumption is not
correct, then the LSP copy of a source file can become slightly out of
sync. If this is an issue, there is some discussion
[here](https://github.com/leanprover/lean4/pull/3903#discussion_r1592930085).
2024-05-20 17:13:08 +00:00
Leonardo de Moura
b278f9dd30 fix: missing withIncRecDepth and unifyEqs? and add support for offsets at unifyEq? (#4224)
Given `h` with type `x + k = y + k'` (or `h : k = k')`, `cases h`
produced a proof of size linear in `min k k'`. `isDefEq` has support for
offset, but `unifyEq?` did not have it, and a stack overflow occurred
while processing the resulting proof. This PR fixes this issue.

closes #4219
2024-05-20 13:42:36 +00:00
Eric Wieser
f0471a519b doc: upstream the Lean4 pygments lexer (#3125)
An improved `lean4` lexer is now part of pygments.

This depends on https://github.com/pygments/pygments/pull/2618 (now
merged), and [a subsequent
release](https://github.com/pygments/pygments/milestone/23)
2024-05-20 11:40:24 +00:00
Alex Keizer
42215cc072 feat: Nat.shiftLeft_shiftRight (#4199)
Show that shifting a natural number left and then shifting right by the
same amount is a no-op.

I originally proved this in a different PR, ended up not needing the
fact after all, but it still seemed like a generally useful simp lemma
to have.
2024-05-20 06:50:28 +00:00
Leonardo de Moura
f53b778c0d feat: improve grind preprocessor (#4221) 2024-05-20 04:29:49 +00:00
Leonardo de Moura
72b345c621 chore: remove #guard_msgs from tests that rely on pointer equality 2024-05-20 06:12:43 +02:00
Mac Malone
6171070deb chore: lake: cloud release build output fixes & related touchups (#4220)
Fixes two output bugs with cloud releases: (1) the fetch as part of an
`extraDep` was not properly isolated in a job, and (2) the release job
would be shown even if the release had already been successfully
fetched.

Also includes some related touchups, including the addition of show all
jobs on `-v` which helps with debugging job counts.
2024-05-20 03:28:50 +00:00
Kim Morrison
7c5249278e chore: move release notes about MessageData to v4.9.0 (#4222) 2024-05-20 01:42:30 +00:00
Leonardo de Moura
239ade80dc chore: update stage0 2024-05-19 07:20:10 +02:00
Leonardo de Moura
47c8e340d6 fix: move cdot and calc parsers to Lean namespace
closes #3168
2024-05-19 07:20:10 +02:00
Leonardo de Moura
c8b72beb4d chore: update stage0 2024-05-19 07:20:10 +02:00
Leonardo de Moura
9803c5dd63 chore: prepare to move cdot and calc parsers to Lean namespace
see issue #3618
2024-05-19 07:20:10 +02:00
Leonardo de Moura
d66d00dece fix: missing occurs-check at delayed assignment (#4217)
closes #4144
2024-05-19 02:53:00 +00:00
JovanGerb
9fde33a09f fix: oversight in isReadOnlyOrSyntheticOpaque (#4206)
### Explanation
In the case that `assignSyntheticOpaque := true` and the given
metavariable is `syntheticOpaque` and the depth of the metavariable is
not the current depth, `isReadOnlyOrSyntheticOpaque` returns false, even
though the metavariable is read-only because of being declared at a
smaller depth. This causes the metavariable to (wrongly) be able to be
instantiated by `isDefEq`.

This bug was found at the proof of
[RingHom.PropertyIsLocal.sourceAffineLocally_of_source_openCover](https://leanprover-community.github.io/mathlib4_docs/Mathlib/AlgebraicGeometry/Morphisms/RingHomProperties.html#RingHom.PropertyIsLocal.sourceAffineLocally_of_source_openCover),
which involves a type class synthesis for `CommRing ?m.2404`, and the
synthesis manages to instantiate this metavariable into different
values, even though `synthInstance?` increases the metavariable depth.
This synthesis fails after 1 second.

I found the bug while modifying the instance synthesis code: the
modified code spent several minutes on this failed synthesis.

### Test
The problem can be verified with the test:
```
run_meta do
  let m ← mkFreshExprMVar (Expr.sort levelOne) MetavarKind.syntheticOpaque
  withAssignableSyntheticOpaque do
  withNewMCtxDepth do
  let eq ← isDefEq m (.const ``Nat [])
  Lean.logInfo m! "{eq}"
```
this unification used to succeed, giving `true`, and this fix makes it
return `false`.

### Impact on Mathlib

This fix causes a change in the behaviour of `congr`, `convert` and
friends, which breaks a couple of proofs in mathlib. Most of these are
fixed by supplying more arguments.

I fixed these proofs, and
[benched](http://speed.lean-fro.org/mathlib4/compare/b821bfd9-3769-4930-b77f-0adc6f9d218f/to/e7b27246-a3e6-496a-b552-ff4b45c7236e?hash2=4f3c460cc1668820c9af8418a87a23db44c7acab)
mathlib. The result is that most files are unaffected, but some files
are significantly improved. This is most prominent in
Mathlib.RingTheory.Jacobson, where the number of instructions has
decreased by 28%. The overall improvement is a 0.3% reduction in
instructions.

[Zulip
message](https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Ways.20to.20speed.20up.20Mathlib/near/439218960)
2024-05-18 21:01:31 +00:00
Kyle Miller
b639d102d1 fix: use maxType when building expression in expression tree elaborator (#4215)
The expression tree elaborator computes a "maxType" that every leaf term
can be coerced to, but the elaborator was not ensuring that the entire
expression tree would have maxType as its type. This led to unexpected
errors in examples such as
```lean
example (a : Nat) (b : Int) :
  a = id (a * b^2) := sorry
```
where it would say it could not synthesize an `HMul Int Int Nat`
instance (the `Nat` would propagate from the `a` on the LHS of the
equality). The issue in this case is that `HPow` uses default instances,
so while the expression tree elaborator decides that `a * b^2` should be
referring to an `Int`, the actual elaborated type is temporarily a
metavariable. Then, when the binrel elaborator is looking at both sides
of the equality, it decides that `Nat` will work and coercions don't
need to be inserted.

The fix is to unify the type of the resulting elaborated expression with
the computed maxType. One wrinkle is that `hasUncomparable` being false
is a valid test only if there are no leaf terms with unknown types (if
they become known, it could change `hasUncomparable` to true), so this
unification is only performed if the leaf terms all have known types.

Fixes issue described by Floris van Doorn on
[Zulip](https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/elaboration.20issue.20involving.20powers.20and.20sums/near/439243587).
2024-05-18 20:59:54 +00:00
Leonardo de Moura
02b6fb3f41 fix: canonInstances := true issue (#4216)
closes #4213
2024-05-18 18:13:41 +00:00
Joachim Breitner
9f6bbfa106 feat: apply’s error message should show implicit arguments as needed (#3929)
luckily the necessary functionality already exists in the form of
`addPPExplicitToExposeDiff`. But it is not cheap, and we should not run
this code
when the error message isn’t shown, so we should do this lazily.

We already had `MessageData.ofPPFormat` to assemble the error message
lazily, but it
was restricted to returning `FormatWithInfo`, a data type that doesn’t
admit a nice
API to compose more complex messages (like `Format` or `MessageData`
has; an attempt to
fix that is in #3926).

Therefore we split the functionality of `.ofPPFormat` into
`.ofFormatWithInfo` and `.ofLazy`,
and use `.ofLazy` to compute the more complex error message of `apply`.

Fixes #3232.

---------

Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
Co-authored-by: Wojciech Nawrocki <wjnawrocki@protonmail.com>
2024-05-18 06:25:43 +00:00
Leonardo de Moura
1ff0e7a2f2 fix: split at h when h has forward dependencies (#4211)
We use an approach similar to the one used in `simp`. 

closes #3731
2024-05-18 02:48:15 +00:00
Leonardo de Moura
3cb6eb0ae6 fix: ensure a local instance is not registered multiple times (#4210)
closes #4203
2024-05-18 02:30:12 +00:00
Alok Singh
489d2d11ec feat: lake: add readme to package templates (#4147)
Messaged @tydeu about adding a README.md to new lake projects. I decided
to add it with the help of GPT.

---------

Co-authored-by: Mac Malone <tydeu@hatpress.net>
2024-05-18 02:02:36 +00:00
Mac Malone
7648bf255c feat: lake: build monitor improvements (#4127)
The new Lake build monitor is now more selective, accurate, and prettier
in what it prints.

**Key Changes:**
 
* Poll jobs at a fixed frequency (100ms), updating the caption and
finished job count.
* Add `action` field to jobs to record information about what jobs do.
It enables distinguishing between jobs which build something, fetch from
a store, or reload logs from the cache.
* At standard verbosity, print build captions only when a job is know to
build or fetch something (i.e., `action >= .fetch`).
* Add an icon and color to job captions based on their log-level / build
status. Also add color to levels in logs.
* Add `--ansi`/`--no-ansi` to toggle Lake's use of ANSI escape codes.
* Fix some `v4.8.0-rc1` bugs and `--old`.

Closes #2822.
2024-05-17 23:20:45 +00:00
Leonardo de Moura
4d2ff6fb04 feat: pretty print Array DiscrTree.Key (#4208) 2024-05-17 22:35:24 +00:00
Leonardo de Moura
ee0bcc8321 feat: add Simp.Config.index (#4202)
The `simp` tactic uses a discrimination tree to select candidate
theorems that will be used to rewrite an expression. This indexing data
structure minimizes the number of theorems that need to be tried and
improves performance. However, indexing modulo reducibility is
challenging, and a theorem that could be applied, when taking reduction
into account, may be missed. For example, suppose we have a `simp`
theorem `foo : forall x y, f x (x, y).2 = y`, and we are trying to
simplify the expression `f a b <= b`. `foo` will not be tried by `simp`
because the second argument of `f a b` is not a projection of a pair.
However, `f a b` is definitionally equal to `f a (a, b).2` since we can
reduce `(a, b).2`.

In Lean 3, we had a much simpler indexing data structure where only the
head symbol was taken into account. For the theorem `foo`, the head
symbol is `f`. Thus, the theorem would be considered by `simp`.

This commit adds the option `Simp.Config.index`. When `simp (config := {
index := false })`, only the head symbol is considered when retrieving
theorems, as in Lean 3. Moreover, if `set_option diagnostics true`,
`simp` will check whether every applied theorem would also have been
applied if `index := true`, and report them. This feature can help users
diagnose tricky issues in code that has been ported from libraries
developed using Lean 3 and then ported to Lean 4. In the following
example, it will report that `foo` is a problematic theorem.

```lean
opaque f : Nat → Nat → Nat

@[simp] theorem foo : f x (x, y).2 = y := by sorry

example : f a b ≤ b := by
  set_option diagnostics true in
  simp (config := { index := false })
```

In the example above, the following diagnostic message is produced.
```lean
[simp] theorems with bad keys
    foo, key: [f, *, Prod.1, Prod.mk, Nat, Nat, *, *]
```

With the information above, users can annotate theorems such as `foo`
using `no_index` for problematic subterms.
Example:
```lean
opaque f : Nat → Nat → Nat

@[simp] theorem foo : f x (no_index (x, y).2) = y := by sorry

example : f a b ≤ b := by
  simp -- `foo` is still applied
```

cc @semorrison 
cc @PatrickMassot
2024-05-17 21:14:58 +00:00
Leonardo de Moura
1382e9fbc4 feat: simprocs for applying shiftLeft_shiftLeft and shiftRight_shiftRight (#4194) 2024-05-16 19:34:46 +00:00
Leonardo de Moura
e8c4540f87 feat: simprocs for reducing x >>> i and x <<< i where i is a bittvector literal (#4193) 2024-05-16 18:16:52 +00:00
FR
f2a304e555 style: fix whitespace and remove duplicate docstring (#4189) 2024-05-16 06:46:39 +00:00
Kim Morrison
3a457e6ad6 chore: use #guard_msgs in run tests (#4175)
Many of our tests in `tests/lean/run/` produce output from `#eval` (or
`#check`) statements, that is then ignored.

This PR tries to capture all the useful output using `#guard_msgs`. I've
only done a cursory check that the output is still sane --- there is a
chance that some "unchecked" tests have already accumulated regressions
and this just cements them!

In the other direction, I did identify two rotten tests:
* a minor one in `setStructInstNotation.lean`, where a comment says `Set
Nat`, but `#check` actually prints `?_`. Weird?
* `CompilerProbe.lean` is generating empty output, apparently indicating
that something is broken, but I don't know the signficance of this file.

In any case, I'll ask about these elsewhere.

(This started by noticing that a recent `grind` test file had an
untested `trace_state`, and then got carried away.)
2024-05-16 00:38:31 +00:00
Alex Keizer
2a966b46f2 feat: bitblasting theorems about unsigned bitvector inequalities (#4178)
This PR adds theorems that relate unsigned bitvector comparisons
`BitVec.ult` and `BitVec.ule` to `BitVec.carry`. These lemmas are a
prerequisite to bit-blasting these comparisons in LeanSAT.
2024-05-16 00:01:31 +00:00
Leonardo de Moura
8204b79b3c fix: cleanup type annotations in congruence theorems (#4185) 2024-05-15 23:50:35 +00:00
Kim Morrison
f63616891f chore: fix bug in omega (#4184)
Fixes #4183
2024-05-15 22:21:17 +00:00
Leonardo de Moura
9a8e7a6411 feat: add cleanupAnnotations parameter to forallTelescope methods (#4180) 2024-05-15 22:19:07 +00:00
JovanGerb
c7741607fb fix: add missing registerTraceClass `Meta.synthInstance.instances (#4151)
The trace class Meta.synthInstance.answer isn't registered, so it can't
be used.

I set `inherited := true`, because I think it is a useful trace to have.
In particular it tells you when an instance has been found that has a
too large size. This is very useful information.
2024-05-15 18:59:01 +00:00
Joachim Breitner
82666e5e7c fix: make erased names in simp clickable (#4176)
as usually, just a matter of using the `WithInfo` variant.

Also simplifying the code a bit, it seems we can use
`realizeGlobalConstNoOverloadWithInfo` here.

(It's somehwatdubious API design that of all the functions in
the `{resolve/realise}GlobalConst{NoOverload,}{WithInfo,}` family
the one with the longest name is the one that should be used
unless one has a reason to use another one.)

Fixes: #4174
2024-05-15 14:12:15 +00:00
Joachim Breitner
aeea7fdf5d fix: List.length_pos no @[simp] (#4172)
in #4158 I was experimenting with a change to the simplifier that
affectes the order in which lemmas were tried, and of course it breaks
proofs all over the place whenever we have a non-confluent simp set.

Among the first breakages encountered, a large fraction was due to
`simp` rewriting with `List.length_pos  : 0 < length l ↔ l ≠ []`.

This does not strike me a as a good simp lemma: If `l` is a manifest
constructor, the simplifier will reduce `length` and solve it anyways,
and if it isn't then an inequality usually isn’t very simp friendly. It
is also highly non-confluent with any kind of `length`-lemma we might
have.

This therefore removes it from the standard simp set.
2024-05-15 13:28:54 +00:00
Leonardo de Moura
3035d2f8f6 feat: grind preprocessor skeleton (#4170) 2024-05-15 04:25:22 +00:00
Leonardo de Moura
3493d066e4 feat: add MVarId.ensureNoMVar (#4169) 2024-05-15 00:37:28 +00:00
Leonardo de Moura
d0e34aaed5 feat: add revertAll tactic for grind (#4167) 2024-05-14 23:22:54 +00:00
Siddharth
367b97885a chore: delete double namespace BitVec.BitVec (#4165)
Fixes double namespace introduced in #4148
2024-05-14 19:34:14 +00:00
Leonardo de Moura
f3538dbdfa feat: grind normalization theorems (#4164) 2024-05-14 19:19:38 +00:00
Leonardo de Moura
770235855f chore: update stage0 2024-05-14 19:52:25 +02:00
Leonardo de Moura
0a515e2ec9 feat: add grind_norm simp attribute for grind tactic 2024-05-14 19:52:25 +02:00
Kim Morrison
91244b2dd9 chore: add dates to @[deprecated] attributes (#3967) 2024-05-14 03:24:57 +00:00
Leonardo de Moura
de5e039c83 fix: type class issues with maxSynthPendingDepth := 1 (#4119)
Summary:

- Take `synthPendingDepth` into account when caching TC results
- Add `maxSynthPendingDepth` option with default := 2.
- Add support for tracking `synthPending` failures when using
`set_option diagnostics true`

closes #2522
closes #3313
closes #3927

Identical to #4114  but with `maxSynthPendingDepth := 1`

closes #4114 

cc @semorrison
2024-05-14 03:03:32 +00:00
Mac Malone
61a84c96db refactor: lake: import errors, job captions, log grouping (#4115)
This improves job captions, the grouping of logs underneath them, and
the handling of import errors. It also adds a number of log-related
utilities to help achieve this.

**Key Changes:**

* Job captions for facets now include the name of the object (e.g.,
module, library, facet). A caption has also been added to the top-level
build of imports (e.g., for the server and `lake lean`).
 
* Stray I/O and errors outside the build job in a build function
captioned with `withRegisterJob` (e.g., user-defined targets) will now
be properly grouped under that caption instead of ending up under
"Computing build jobs". Stray I/O will be converted to a single
informational log entry.

* Builds no longer fail immediately on erroneous imports. Lake will now
attempt to recover as best as possible from any import errors.
Information on the import error will appear both in the build of the
erroneous import and in the files which transitive import it. For
example, uf `Lib.B` imports a missing module `Lib.A`, then the build of
`Lib.A` will mention that the file does not exist, and the build of
`Lib.B` will mention the bad import of `Lib.A`.

Closes #3351. Closes #3809.
2024-05-13 22:11:18 +00:00
Leonardo de Moura
98b2681d0e perf: simplify canonicalizer (#4155) 2024-05-13 19:45:20 +00:00
Joachim Breitner
7c4284aa91 refactor: no need for simpMatchWF? (#4153)
Despite what it said in its docstring, `simpMatchWF?` seems to behave
like `simpMatch?`, so let’s just use that.
2024-05-13 19:33:23 +00:00
Joachim Breitner
842280321b refactor: let Nat.mod reduce more (#4145)
this refined upon #4098 and makes `Nat.mod` reduce on even more
literals. The key observation that I missed earlier is that `if m ≤ n`
reduces better than `if n < m`.

Also see discussion at

https://github.com/leanprover-community/mathlib4/pull/12853#discussion_r1597798308
2024-05-13 16:41:09 +00:00
Joachim Breitner
d833f82fe8 chore: rerun CI only when full-ci label is added or removed (#4136)
Previously, the CI would run upon every label addition, including things
like `builds-mathlib`
or `will-merge-soon`, possibly triggering a new PR release, new mathlib
builds etc. Very wasteful!

Unfortunately (but not surprisingly) Github does not offer a nice way of
saying
“this workflow depends on that label, please re-run if changed”. Not
enough
functional programmer or nix enthusiasts there, I guess…

So here is the next iteration trying to work with what we have from
Github:

A new workflow watches for (only) `full-ci` label addition or deletion,
and then re-runs
the CI job for the current PR.

Sounds simple? But remember, this is github!

* `github.event.pull_request.labels.*.name` is *not* updated when a job
is re-run.

(This is actually a reasonable step towards determinism, but doesn't
help us
   constructing this work-around.)
   
   Ok, so let’s use the API to fetch the current state of the label.

* There is no good way to say “find the latest run of workflow `"CI"` on
PR `$n`”.

The best approximation seems to search by branch and triggering event.
This can
probably go wrong if there are multiple PRs from different repos with
the same
head ref name (`patch-1` anyone?). Let’s hope that it doesn’t happen too
often.

* You cannot just rerun a workflow. You can only rerun a finished
workflow. So cancel
  it first. And `sleep` a bit…

So let’s see how well this will work. It’s plausibly an improvement.
2024-05-13 16:40:36 +00:00
Siddharth
a17c3f424c feat: BitVec.shiftLeft_shiftLeft, BitVec.shiftRight_shiftRight (#4148)
Closes two `sorry`s at
https://github.com/leanprover/leansat/pull/64/files.

---------

Co-authored-by: Kim Morrison <scott@tqft.net>
2024-05-13 12:35:59 +00:00
Kim Morrison
799923d145 chore: move have to decreasing_by in substrEq.loop (#4143)
Currently this causes linter warnings downstream in proofs that unfold
substrEq.loop.
2024-05-13 06:18:44 +00:00
Kim Morrison
f74980ccee chore: incorrect lemma resolution in omega (#4141)
Fixes #4138.
2024-05-12 23:06:48 +00:00
Joachim Breitner
b8f2f28e0d fix: check that funind-reserved names are available (#4135)
I did not introduce `inductTheoremSuffix` etc, it seems more direct to
just spell out the suffix here. If we ever change it there are many
occurrences where they need to be changed anyways, so the definition
doesn't seem to save much work or add that much robustness.
2024-05-12 20:39:14 +00:00
Marcus Rossel
0d9af1b777 fix: typo in Meta.unfoldProjInstWhenInstances? (#4139) 2024-05-12 16:45:56 +00:00
Leonardo de Moura
7db8e6482e fix: auto/option params should not break sorry (#4132)
closes #2649
2024-05-11 02:10:40 +00:00
Leonardo de Moura
147aeaea45 test: for issue 2558 (#4133)
Issue has been fixed by another PR.

closes #2558
2024-05-11 00:47:33 +00:00
Leonardo de Moura
a875ae3acf feat: recover from runtime errors in tactics (#4130)
closes #3554
2024-05-11 00:07:13 +00:00
Mac Malone
25e94f916f feat: IO.TaskState (#4097)
Adds `IO.getTaskState` which returns the state of a `Task` in the Lean
runtime's task manager. The `TaskState` inductive has 3 constructors:
`waiting`, `running`, and `finished`. The `waiting` constructor
encompasses the waiting and queued states within the C task object
documentation, because the task object does not provide a low cost way
to distinguish these different forms of waiting. Furthermore, it seems
unlikely for consumers to wish to distinguish between these internal
states. The `running` constructor encompasses both the running and
promised states in C docs. While not ideal, the C implementation does
not provide a way to distinguish between a running `Task` and a waiting
`Promise.result` (they both have null closures).
2024-05-10 23:04:54 +00:00
Kyle Miller
a1be9ec850 chore: tidying up Lean.unresolveNameGlobal (#4091)
The main loop logic could be simplified, and `if let` could be used to
make control flow more obvious.

Also adds a check for macro scopes to prevent `unresolveNameGlobal` from
returning names with macro scopes in the event there's an alias with
one.

This is a follow up to #3946.
2024-05-10 22:37:34 +00:00
Leonardo de Moura
e237e12478 refactor: add tryCatchRuntimeEx combinator (#4129)
see #4079
2024-05-10 22:34:09 +00:00
Leonardo de Moura
a6d186a81d fix: add checkSystem and withIncRecDepth to withAutoBoundImplicit (#4128)
Fix stack overflow crash.

Closes #4117

The fix can be improved: we could try to avoid creating hundreds of auto
implicits before failing.
2024-05-10 21:55:26 +00:00
Arthur Adjedj
6c6b56e7fc fix: revert "monadic generalization of FindExpr" (#4125)
This reverts commit 706a4cfd73 introduced
in #3970

As explained in #4124, `findM?` can become a footgun if used in monads
which induce side-effects such as caching. This PR removes that
function, and fixes the code introduced by #3398 for which the function
was first added.

cc @semorrison.
2024-05-10 20:36:08 +00:00
JovanGerb
228ff58f3a chore: remove duplicate check (#4126) 2024-05-10 20:35:21 +00:00
Lean stage0 autoupdater
dcdc3db3d4 chore: update stage0 2024-05-10 07:39:47 +00:00
Joachim Breitner
39286862e3 feat: well-founded definitions irreducible by default (#4061)
we keep running into examples where working with well-founded recursion
is slow because defeq checks (which are all over the place, including
failing ones that are back-tracked) unfold well-founded definitions.

The definition of a function defined by well-founded recursion should be
an implementation detail that should only be peeked inside by the
equation generator and the functional induction generator.

We now mark the mutual recursive function as irreducible (if the user
did not
set a flag explicitly), and use `withAtLeastTransparency .all` when
producing
the equations.

Proofs can be fixed by using rewriting, or – a bit blunt, but nice for
adjusting
existing proofs – using `unseal` (a.k.a. `attribute [local
semireducible]`).

Mathlib performance does not change a whole lot:

http://speed.lean-fro.org/mathlib4/compare/08b82265-75db-4a28-b12b-08751b9ad04a/to/16f46d5e-28b1-41c4-a107-a6f6594841f8
Build instructions -0.126 %, four modules with significant instructions
decrease.

To reduce impact, these definitions were changed:

* `Nat.mod`, to make `1 % n` reduce definitionally, so that `1` as a
`Fin 2` literal
works nicely. Theorems with larger `Fin` literals tend to need a `unseal
Nat.modCore`
   https://github.com/leanprover/lean4/pull/4098
* `List.ofFn` rewritten to be structurally recursive and not go via
`Array.ofFn`:
   https://github.com/leanprover-community/batteries/pull/784

Alternative designs explored were

 * Making `WellFounded.fix` irreducible. 
 
One benefit is that recursive functions with equal definitions (possibly
after
instantiating fixed parameters) are defeq; this is used in mathlib to
relate

[`OrdinalApprox.gfpApprox`](https://leanprover-community.github.io/mathlib4_docs/Mathlib/SetTheory/Ordinal/FixedPointApproximants.html#OrdinalApprox.gfpApprox)
with `.lfpApprox`.
   
   But the downside is that one cannot use `unseal` in a
targeted way, being explicit in which recursive function needs to be
reducible here.

And in cases where Lean does unwanted unfolding, we’d still unfold the
recursive
definition once to expose `WellFounded.fix`, leading to large terms for
often no good
   reason.

* Defining `WellFounded.fix` to unroll defintionally once before hitting
a irreducible
`WellFounded.fixF`. This was explored in #4002. It shares most of the
ups and downs
with the previous variant, with the additional neat benefit that
function calls that
do not lead to recursive cases (e.g. a `[]` base case) reduce nicely.
This means that
   the majority of existing `rfl` proofs continue to work.

Issue #4051, which demonstrates how badly things can go if wf recursive
functions can be
unrolled, showed that making the recursive function irreducible there
leads to noticeably
faster elaboration than making `WellFounded.fix` irreducible; this is
good evidence that
the present PR is the way to go. 

This fixes https://github.com/leanprover/lean4/issues/3988

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-05-10 06:45:21 +00:00
Mac Malone
ca6437df71 fix: lake: TOML key order bug in ppTable (#4104)
Fixes a bug in `Lake.Toml.ppTable` where root table keys could be
printed after a subtable header.

Closes #4099.
2024-05-10 05:12:19 +00:00
Mario Carneiro
3491c56c49 fix: segfault in old compiler due to noConfusion assumptions (#2903)
This fixes #2901, a bug in the old compiler which causes a segfault. The
issue is that when visiting `noConfusion` applications, it assumes that
each constructor case has `nfields` arguments, e.g. `head1 = head2 ->
tail1 = tail2 -> P` has two arguments because `List.cons` has 2 fields,
but in fact propositional fields are skipped by the noConfusion type
generator, so for example `Subtype.noConfusionType` is:
```lean
@[reducible] protected def Subtype.noConfusionType.{u_1, u} : {α : Sort u} →
  {p : α → Prop} → Sort u_1 → Subtype p → Subtype p → Sort u_1 :=
fun {α} {p} P v1 v2 ↦
  Subtype.casesOn v1 fun val property ↦ Subtype.casesOn v2 fun val_1 property ↦ 
    (val = val_1 → P) → P
```
where `val = val_1 → P` only has the one argument even though
`Subtype.mk` has two fields, presumably because it is useless to have an
equality of propositions. Unfortunately there isn't any easy cache or
getter to use here to get the number of non-propositional fields, so we
just calculate it on the spot.
2024-05-10 01:38:38 +00:00
Tobias Grosser
368adaf847 feat: add BitVec.[toInt_inj|toInt_ne] (#4075)
Co-authored-by: Kim Morrison <scott@tqft.net>
2024-05-10 00:57:00 +00:00
Leonardo de Moura
6a040ab068 feat: propagate maxHeartbeats to kernel (#4113)
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-05-09 17:44:19 +00:00
Kim Morrison
fe7b96d8a0 fix: generate deprecation warnings for dot notation (#3969)
Fixes #3270 by moving the deprecation check from
`Lean.Elab.Term.mkConsts` to `Lean.Elab.Term.mkConst`, so
`Lean.Elab.Term.mkBaseProjections`, `.elabAppLValsAux`, `.elabAppFn`,
and `.elabForIn` also hit the check. Not all of these really need to hit
the check, so I'll run `!bench` to see if it's a problem.
2024-05-09 04:52:09 +00:00
Leonardo de Moura
ec87283465 perf: use withSynthesize when elaborating let/have type (#4096)
closes #4051

cc @semorrison
2024-05-09 00:58:43 +00:00
Leonardo de Moura
d7c6920550 chore: remove dead functionpreprocessLevels (#4112) 2024-05-08 15:38:04 +00:00
Joachim Breitner
227e861719 refactor: make 1 % n reduce without well-founded recursion (#4098)
this is in preparation for #4061. Once that lands, `1 % 42 = 1` will no
longer hold definitionally (at least not without an ungly `unseal
Nat.modCore in` around). This affects mathlib in a few places,
essentially every time a `1 : Fin (n+1)` literal is written.

So this extends the existing special case for `0 % n = 0` to `1 % n`.
2024-05-08 15:12:47 +00:00
Joachim Breitner
e9c302c17e chore: bug template: point to live.lean-lang.org (#4109)
https://live.lean-lang.org/#project=lean-nightly now allows users to
play around with the latest lean nightly, and it seems prudent to ask
them to test bug reports, if possible, there, and not just with whatever
release they use.

Also reformatted the descriptions to look well in a text area. Users
will not see this as rendered markdown, but as plain text.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-05-08 13:21:17 +00:00
Mario Carneiro
5814a45d44 fix: mainModuleName should use srcSearchPath (#4066)
As [reported on
Zulip](https://leanprover.zulipchat.com/#narrow/stream/341532-lean4-dev/topic/Find.20references.20broken.20in.20lean.20core/near/437051935).
The `mainModuleName` was being set incorrectly when browsing lean core
sources, resulting in failure of cross-file server requests like "Find
References". Because the `srcSearchPath` is generated asynchronously, we
store it as a `Task Name` which is resolved some time before the header
is finished parsing. (I don't think the `.get` here will ever block,
because the srcSearchPath will be ready by the time the initial command
snap is requested.)

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-05-08 12:34:27 +00:00
Kim Morrison
dcf74b0d89 chore: Std -> Batteries renaming (#4108) 2024-05-08 05:04:25 +00:00
Kyle Miller
a257767417 fix: make deriving handler for Repr be consistent about erasing types and proofs (#3944)
The deriving handler would use `_` for types and proofs for structures
but not for inductives.

Reported by Graham Leach-Krouse on
[Zulip](https://leanprover.zulipchat.com/#narrow/stream/113489-new-members/topic/Deriving.20Repr.20for.20an.20inductive.20with.20proof.20parameters/near/434181985).
2024-05-07 23:55:52 +00:00
Austin Letson
b8e67d87a8 doc: add docstrings and usage examples in Init.Data.String.Basic (#4001)
Add docstrings and usage examples for `String.length`, `.push`,
`.append`, `.get?`, `.set`, `.modyify`, and `.next`. Update docstrings
and add usage examples for `String.toList`, `.get`, and `.get!`.

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-05-07 23:49:43 +00:00
Leonardo de Moura
2a5ca00ad6 perf: issue at binop% and binrel% elaborators (#4092)
This issue was affecting several Mathlib files.

@mattrobball @semorrison This is a different solution for the issue. The
comment at `Extra.lean` describes the new solution and documents the new
issues found with the previous one.

closes #4085
2024-05-07 23:31:05 +00:00
François G. Dorais
ec27b3760d fix: swap Nat.zero_or and Nat.or_zero (#4094)
Closes #4093
2024-05-07 23:29:38 +00:00
Siddharth
e5b7dc819b feat: bitvec lemma to turn negation into bitwise not+add (#4095)
Identity 2-2 (a) (Section: Addition Combined with Logical Operations)
from Hacker's Delight, 2nd edition.
2024-05-07 22:31:19 +00:00
Leonardo de Moura
93c06c0552 feat: relaxed reset/reuse in the code generator (#4100)
closes #4089
2024-05-07 22:08:32 +00:00
Mario Carneiro
bb7e6e4769 chore: lake: tweak hovers for family_def et al (#4088)
This makes the `leanArts` in `library_data leanArts : BuildJob Unit` get
a hover for the generated axiom. It also simplifies the `quoteFrom`
function so that it delaborates properly by using a name literal (which
elaborates to `mkStr1`, `mkStr2` etc) instead of a `mkStr` application.
2024-05-07 15:14:09 +00:00
Kim Morrison
883a3e752d chore: allow omega to use classicality, in case Decidable instances are too big (#4073)
From bug report at
https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/omega.20regression.20in.204.2E8.2E0-rc1/near/437150155
2024-05-07 01:44:56 +00:00
Leonardo de Moura
03040618b8 chore: test for issue #4064
closes #4064
2024-05-07 03:23:30 +02:00
Leonardo de Moura
dfde4ee3aa chore: update stage0 2024-05-07 03:23:30 +02:00
Leonardo de Moura
07c407ab82 feat: collect kernel diagnostic information (#4082)
We now also track which declarations have been unfolded by the kernel
when using
```lean
set_option diagnostics true
```
2024-05-06 21:53:16 +00:00
Leonardo de Moura
00dceb9a9d fix: code duplication at liftCoreM and liftTermElabM at Command.lean (#4080)
This PR also fixes:

- Fields caching specific `Options` at `CoreM` are now properly set.
- `nextMacroScope` was not being propagated at `liftCoreM`.
2024-05-06 19:17:35 +00:00
Kim Morrison
35d9307df3 chore: move @[simp] attribute on length_eq_zero earlier (#4077)
Cleanup.
2024-05-06 11:14:18 +00:00
Kyle Miller
9e4c414f48 fix: remove Subtype.instInhabited (#4055)
It has had a long history going back [10
years](3afad10a72 (diff-4e22e2bb74f004d2ff7cdabcb5c01429abbc906e20befe2517679e257b4387e4R41)),
but its time has come to an end since this instance is never applicable.
2024-05-06 11:08:19 +00:00
Joachim Breitner
6d22793ddf refactor: Array.feraseIdx: avoid have in definition (#4074)
otherwise it remains in the equational theorem and may cause the
“unused have linter” to trigger. By moving the proof into
`decreasing_by`, the equational theorems are unencumbered by termination
arguments.

see also
https://github.com/leanprover/std4/pull/690#issuecomment-2095378609
2024-05-06 08:08:43 +00:00
Arthur Adjedj
e0c1afd12d fix: occurence check in mkInjectiveTheoremTypeCore? (#3398)
Closes #3386

Currently, when generating the signature of an injectivity lemma for a
certain constructor `c : forall xs, Foo a_1 ... a_n`,
`mkInjectiveTheoremTypeCore?` will differentiate between variables which
are bound to stay the same between the two equal values (i.e inductive
indices), and non-fixed ones. To do that, the function currently checks
whether a variable `x ∈ xs` appears in the final co-domain `Foo a_1 ...
a_n` of the constructor. This condition isn't enough however. As shown
in the linked issue, the codomain may also depend on variables which
appears in the type of free vars contained in `Foo a_1 ... a_n`, but not
in the term itself. This PR fixes the issue by also checking the types
of any free variable occuring in the final codomain, so as to ensure
injectivity lemmas are well-typed.
2024-05-06 06:50:08 +00:00
Harun Khan
b1bedbe0d2 feat: equivalence of bit-vector negation and bitblasted negation (#3920) 2024-05-06 06:03:28 +00:00
Arthur Adjedj
1ea92baa21 fix: Incorrect promotion from index to paramater (#3591)
Depends on #3590

Closes #3458
2024-05-06 05:58:15 +00:00
Peiran Wu
07be352ea7 feat: lemmas to simplify equalities with Option-typed dependent if-then-else (#4037)
Closes #4013.

Add `dite_some_none_eq_none` and `dite_some_none_eq_some`, analogous to
the existing `ite_some_none_eq_none` and `ite_some_none_eq_some`.
2024-05-06 05:51:52 +00:00
Kim Morrison
3c11cca3cb feat: upstream lemmas about basic List/Array operations (#4059)
This PR upstreams lemmas about List/Array operations already defined in
Lean from std/batteries.

Happy to take suggestions about increasing or decreasing scope.

---------

Co-authored-by: Mario Carneiro <di.gama@gmail.com>
2024-05-06 03:52:33 +00:00
Kyle Miller
3bd2a7419d fix: have app unexpanders be considered before field notation (#4071)
On
[Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Notation.20in.20namespace.20not.20showing.20in.20pp/near/437016468),
Peter Nelson reported that notations that could be pretty printed with
generalized field notation did not pretty print using the intended
notation.

This PR makes it so that app unexpanders are considered before
generalized field notation. The complexity before was that we wanted to
do parent projection collapse, and since we did the collapse before
pretty printing that argument, it meant it wasn't possible to do app
unexpanders when there was a field notation candidate. The new solution
is to collapse parent projections only when actually considering field
notation, which can be done because we can safely strip off projection
syntax in an expression-directed way.
2024-05-05 22:44:01 +00:00
Joachim Breitner
26a1b934c2 fix: rfl tactic error messsage when there are no goals (#4067)
fixes #4063
2024-05-05 10:42:41 +00:00
Mario Carneiro
93d7afb00a fix: bug in reduceLeDiff simproc proof term (#4065)
As [reported on
Zulip](https://leanprover.zulipchat.com/#narrow/stream/348111-std4/topic/v4.2E8.2E0-rc1.20issue/near/437059527).
2024-05-05 07:44:36 +00:00
Leonardo de Moura
e362b50fa9 feat: add seal and unseal commands (#4053) 2024-05-03 13:44:58 +00:00
Leonardo de Moura
2df35360ee feat: validate reducibility attribute setting (#4052)
and new option `set_option allowUnsafeReductibility true` to override
validation.

---------

Co-authored-by: Mario Carneiro <di.gama@gmail.com>
2024-05-03 13:44:42 +00:00
Mario Carneiro
2db602c209 doc: layout algorithm (#3915)
The layout algorithm, while somewhat finicky, is (unfortunately)
necessary for C code to interface with lean structures. This adds a
(AFAIK) complete description of the layout algorithm, including a worked
example large enough to make it possible to reconstruct the whole
decision diagram.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-05-03 11:47:23 +00:00
Mario Carneiro
00cf5771f3 feat: support idents in auto tactics (#3328)
This is still experimental, but it implements identifier support in auto
tactics "in the obvious way". It also converts `quoteAutoTactic` to
generate Expr directly instead of going via syntax (this doesn't have
any effect other than increasing compile cost AFAICT).
2024-05-03 04:37:07 +00:00
Kim Morrison
51abb0d4c7 chore: begin development cycle for v4.9.0 (#4058) 2024-05-03 03:20:29 +00:00
Mac Malone
e733149134 feat: lake: require doc comments (#4057)
Lake now supports docstrings on `require` commands:

```lean
/-- This is a docstring for a require statement. -/
require std from ...
```

Closes #2898.
2024-05-03 01:08:18 +00:00
Mac Malone
ac08be695e chore: lake: cleanup tests (#4056)
Various tweaks and fixes to the Lake tests to make them cleaner and more
standardized.
2024-05-03 01:08:12 +00:00
Leonardo de Moura
1d17c7df2b chore: cleanup and remove unnecessary checkpointDefEq (#4029) 2024-05-02 17:58:03 +00:00
Sebastian Ullrich
092ca8530a chore: CI: disable large runner again 2024-05-02 17:46:29 +02:00
Sebastian Ullrich
92fac419e7 chore: CI: use large runners on Windows (#4050) 2024-05-02 14:28:17 +00:00
Mac Malone
e6160d7d4a feat: IO.Process.get/setCurrentDir (#4036)
Adds `IO.Process.getCurrentDir` and `IO.Process.setCurrentDir` for
retrieving and setting, respectively, the current working directory of a
process. The names of the functions are inspired by Rust (e.g.,
[`set_current_dir`](https://doc.rust-lang.org/std/env/fn.set_current_dir.html)).
2024-05-02 13:49:10 +00:00
Joachim Breitner
74adb0961c chore: add ./script/rebase-stage0.sh (#3984)
heavily based on an script by Kim.
2024-05-02 12:26:25 +00:00
Sebastian Ullrich
4591747381 feat: trace.profiler.useHeartbeats (#3986)
Makes trace.profiler useful for debugging heartbeat timeouts etc.. Not
an exact science as enabling profiling consumes itself but close enough.
2024-05-02 12:09:19 +00:00
Joachim Breitner
bc23383194 feat: subst notation (heq ▸ h) tries both orientation (#4046)
even when rewriting the type of `h` becuase there is no expected type.

(When there is an expected type, it already tried both orientations.)

Also feeble attempt to include this information in the docstring without
writing half a manual chapter.
2024-05-02 07:02:40 +00:00
Joachim Breitner
b470eb522b refactor: do not try rfl in mkEqnTypes in WF.mkEqns (#4047)
when dealing with well-founded recursive definitions, `tryURefl` isn't
going to be that useful and possibly slow. So disable that code path
when doing well-founded recursion.

(This is a variant of #4025 where I tried using `with_reducible` to
limit the impact of slow unfolding, but if we can get away with
disabling it complete, then even better.)
2024-05-02 06:17:15 +00:00
Kim Morrison
e13613d633 chore: report used instances correctly in diagnostics (#4049) 2024-05-02 05:47:51 +00:00
Leonardo de Moura
5f1c4df07d feat: display diagnostic information at term and tactic set_option diagnostics true (#4048)
We don't need to include reduction info at `simp` diagnostic
information.
2024-05-01 22:47:57 +00:00
Kyle Miller
5f727699b0 doc: mention build doc source location (#4045) 2024-05-01 22:42:54 +00:00
Leonardo de Moura
e1b7984836 perf: improve simp cache behavior for well-behaved dischargers (#4044)
See comment at `Methods.wellBehavedDischarge`.
The default discharger is now well-behaved.
2024-05-01 19:57:44 +00:00
Leonardo de Moura
d9ea092585 feat: include congruence theorems at simp diagnostic information (#4043) 2024-05-01 17:22:24 +00:00
Kyle Miller
359f60003a fix: use correct expr positions when delaborating match patterns (#4034)
In the following, hovering over `true` in the infoview was showing
`Nat.succ y`.
```lean
#check fun (x : Nat) =>
  match h : x with
  | 0 => false
  | y + 1 => true
```
Now hovering over `true` shows `true`.

The issue was that SubExpr positions were not being tracked for
patterns, and the position for a pattern could coincide with the
position for a RHS, putting overwriting terminfo. Now the position given
to a pattern is correct and unique.

Refactors the `match` delaborator, makes it handle shadowing of `h :`
discriminant annotations correctly, and makes it use the standard
`withOverApp` combinator to handle overapplication.
2024-05-01 12:02:10 +00:00
Leonardo de Moura
806e41151b chore: fix tests 2024-05-01 03:19:39 +02:00
Leonardo de Moura
527493c2a1 feat: in tried theorem section at simp diagnostics, indicate how many times is succeeded 2024-05-01 03:19:39 +02:00
Leonardo de Moura
a12e8221da feat: include counters for unfolded declarations at simp diagnostics 2024-05-01 03:19:39 +02:00
Leonardo de Moura
bcfad6e381 feat: report diagnostic information for simp at exception 2024-05-01 03:19:39 +02:00
Leonardo de Moura
283587987a feat: diagnostic information for simp 2024-05-01 03:19:39 +02:00
Leonardo de Moura
99e652ab1c feat: mention set_option diagnostics true at maximum recursion depth error message 2024-05-01 03:19:39 +02:00
Leonardo de Moura
c833afff11 feat: mention set_option diagnostics true at deterministic timeout message 2024-05-01 03:19:39 +02:00
Leonardo de Moura
c3714bdc6d feat: add structure to diagnostic information 2024-05-01 03:19:39 +02:00
Mac Malone
cc2ccf71d5 fix: lake: log refactor bugs (#4033)
Fixes some bugs with the log refactor (#3835). Namely, quiet mode
progress printing and missing string interpolation in the fetching cloud
release caption.
2024-04-30 23:25:32 +00:00
Kim Morrison
f8d2ebd47a chore: remove @[simp] from BitVec.of_length_zero (#4039) 2024-04-30 23:19:27 +00:00
Kim Morrison
660eb9975a chore: restore #4006 (#4038) 2024-04-30 23:06:50 +00:00
Leonardo de Moura
5c3f6363cc fix: mismatch between TheoremVal in Lean and C++ (#4035) 2024-04-30 18:10:20 +00:00
Sebastian Ullrich
6e731b4370 chore: delete interpreter copy constructor just to be safe 2024-04-30 10:36:40 +02:00
Sebastian Ullrich
18a69914da chore: fix asan linking 2024-04-30 10:36:19 +02:00
Leonardo de Moura
83c139f750 feat: improve set_option diagnostics true (#4031) 2024-04-30 05:07:03 +00:00
Leonardo de Moura
edbd7ce00d chore: rename set_option diag true to set_option diagnostics true (#4030) 2024-04-30 03:57:57 +00:00
Mac Malone
02925447bd refactor: lake: --wfail & track jobs & logs & simplify build monads (#3835)
This is a major refactor of Lake's build code.  The key changes:

* **Job Registration**: Significant build jobs are now registered by
build functions. The DSL inserts this registration automatically into
user-defined targets and facets, so this change should require no
end-user adaption. Registered jobs are incrementally awaited by the main
build function and the progress counter now indicates how many of these
jobs are completed and left-to-await. On the positive side, this means
the counter is now always accurate. On the negative side, this means
that jobs are displayed even if they are no-ops (i.e., if the target is
already up-to-date).

* **Log Retention**: Logs are now part of a Lake monad's state instead
of being eagerly printed. As a result, build jobs retain their logs.
Using this change, logs are are now always printed after their
associated caption (e.g., `[X/Y] Building Foo`) and are not arbitrarily
interleaved with the output of other jobs.

* **Simplify the build monad stack**: Previously, there was a lot of
confused mixing between the various build monads in the codebase (i.e.,
`JobM`, `ScedulerM`, `BuildM`, `RecBuildM`, and `IndexBuildM` ). This
refactor attempts to make there use more consistent and straightforward:
* `FetchM` (formerly `IndexBuildM`) is the top-level build monad used by
targets and facets and is now uniformly used in the codebase for all
top-level build functions.
* `JobM` is the monad of asynchronous build jobs. It is more limited
than `FetchM` due to the fact that the build cache can not be modified
asynchronously.
* `SpawnM` (formerly `SchedulerM`) is the monad used to spawn build
jobs. It lifts into `FetchM`.
* `RecBuildM` and `CoreBuildM` (formerly `BuildM`) have been relegated
to internal details of how `FetchM` / `JobM` are implemented / run and
are no longer used outside of that context.

* **Pretty progress.** Build progress (e.g., `[X/Y] Building Foo`) is
now updated on a single line via ANSI escape sequences when Lake is
outputting to a terminal. Redirected Lake output still sees progress on
separate lines.

* **Warnings-as-error option.** Adds a `--wfail` option to Lake that
will cause a build to fail if Lake logs any warnings doing a build.
Unlike some systems, this does not convert warnings into errors and it
does not abort jobs which log warnings. Instead, only the top-level
build fails.

* **Build log cache.** Logs from builds are now cached to a file and
replayed when the build is revisited. For example, this means multiple
runs of a `--wfail` Lean build (without changes) will still produce the
same warnings even though there is now an up-to-date `.olean` for the
module.

 Closes #2349. Closes #2764.
2024-04-30 01:55:20 +00:00
Mac Malone
a969d2702f chore: lake: error on package name mismatch + std special case (#3999)
Lake now errors instead of warns on a mismatch between a package name
and what is required as. This avoids sometimes confusing downstream
errors. Also, this change provides additional information for errors
that may be caused by the upcoming Std rename.
2024-04-30 01:32:35 +00:00
Leonardo de Moura
27c79cb614 fix: double reset bug at ResetReuse (#4028)
We conjecture this is the cause for the segfaults when compiling Mathlib
with #4006
2024-04-29 23:26:07 +00:00
Joachim Breitner
e2983e44ef perf: use with_reducible in special-purpose decreasing_trivial macros (#3991)
Because of the last-added-tried-first rule for macros, all the special
purpose `decreasing_trivial` rules are tried for most recursive
definitions out there, and because they use `apply` and `assumption`
with default transparency may cause some definitoins to be unfolded over
and over again.

A quick test with one of the functions in the leansat project shows that
elaboration time goes down from 600ms to 375ms when using
```
decreasing_by all_goals decreasing_with with_reducible decreasing_trivial
```
instead of
```
decreasing_by all_goals decreasing_with decreasing_trivial
```

This change uses `with_reducible` in most of these macros.

This means that these tactics will no longer work when the
relations/definitions they look for is hidden behind a definition.
This affected in particular `Array.sizeOf_get`, which now has a
companion `sizeOf_getElem`.

In addition, there were three tactics using `apply` to apply Nat-related
lemmas
that we now expect `omega` to solve. We still need them when building
`Init` modules
that don’t have access to `omega`, but they now live in
`decreasing_trivial_pre_omega`,
meant to be only used internally.
2024-04-29 15:12:27 +00:00
Kim Morrison
01573067f9 chore: typos (#4026) 2024-04-29 14:04:50 +00:00
Joachim Breitner
f0b2621047 test: add guard_msgs to wfEqns tests (#4024)
otherwise we would not catch changes to the shape of these equational
lemmas.

Also, no need to manually trigger the generation of these lemmas.
2024-04-29 12:45:53 +00:00
Leonardo de Moura
4b88965363 chore: disable #4006 (#4021)
Mathlib is crashing with #4006. Here is the stacktrace produced by Kim:
```
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x100000000000a)
  * frame #0: 0x00000001066db21c libleanshared.dylib`lean::ir::interpreter::eval_body(lean::object_ref const&) + 2816
    frame #1: 0x00000001066dd464 libleanshared.dylib`lean::ir::interpreter::call(lean::name const&, lean::array_ref<lean::object_ref> const&) + 1360
    frame #2: 0x00000001066db394 libleanshared.dylib`lean::ir::interpreter::eval_body(lean::object_ref const&) + 3192
    frame #3: 0x00000001066dd464 libleanshared.dylib`lean::ir::interpreter::call(lean::name const&, lean::array_ref<lean::object_ref> const&) + 1360
    frame #4: 0x00000001066db394 libleanshared.dylib`lean::ir::interpreter::eval_body(lean::object_ref const&) + 3192
    frame #5: 0x00000001066dd464 libleanshared.dylib`lean::ir::interpreter::call(lean::name const&, lean::array_ref<lean::object_ref> const&) + 1360
    frame #6: 0x00000001066db394 libleanshared.dylib`lean::ir::interpreter::eval_body(lean::object_ref const&) + 3192
    frame #7: 0x00000001066df288 libleanshared.dylib`lean::ir::interpreter::stub_m(lean_object**) + 556
    frame #8: 0x00000001066d6ee0 libleanshared.dylib`lean_object* lean::ir::interpreter::with_interpreter<lean_object*>(lean::environment const&, lean::options const&, lean::name const&, std::__1::function<lean_object* (lean::ir::interpreter&)> const&) + 320
    frame #9: 0x00000001066dee84 libleanshared.dylib`lean::ir::interpreter::stub_m_aux(lean_object**) + 92
    frame #10: 0x00000001066deafc libleanshared.dylib`lean::ir::interpreter::stub_9_aux(lean_object*, lean_object*, lean_object*, lean_object*, lean_object*, lean_object*, lean_object*, lean_object*, lean_object*) + 60
    frame #11: 0x00000001066f52a0 libleanshared.dylib`lean_apply_6 + 1748
    frame #12: 0x00000001055d1ac8 libleanshared.dylib`l_Array_forInUnsafe_loop___at___private_Lean_Elab_Term_0__Lean_Elab_Term_applyAttributesCore___spec__10___lambda__2 + 156
    frame #13: 0x00000001055d47e8 libleanshared.dylib`l_Array_forInUnsafe_loop___at___private_Lean_Elab_Term_0__Lean_Elab_Term_applyAttributesCore___spec__10___lambda__2___boxed + 144
    frame #14: 0x00000001066f5bcc libleanshared.dylib`lean_apply_7 + 1348
    frame #15: 0x00000001055ccccc libleanshared.dylib`l_Lean_Elab_withInfoTreeContext___at___private_Lean_Elab_Term_0__Lean_Elab_Term_applyAttributesCore___spec__4 + 528
    frame #16: 0x00000001066f5b6c libleanshared.dylib`lean_apply_7 + 1252
    frame #17: 0x00000001055d1550 libleanshared.dylib`l_Lean_Elab_withLogging___at___private_Lean_Elab_Term_0__Lean_Elab_Term_applyAttributesCore___spec__6 + 240
    frame #18: 0x00000001055d4cb4 libleanshared.dylib`l_Array_forInUnsafe_loop___at___private_Lean_Elab_Term_0__Lean_Elab_Term_applyAttributesCore___spec__10 + 940
    frame #19: 0x00000001055d5394 libleanshared.dylib`l___private_Lean_Elab_Term_0__Lean_Elab_Term_applyAttributesCore___lambda__1 + 60
    frame #20: 0x00000001055d5740 libleanshared.dylib`l___private_Lean_Elab_Term_0__Lean_Elab_Term_applyAttributesCore___lambda__1___boxed + 148
    frame #21: 0x00000001066f11f4 libleanshared.dylib`lean_apply_1 + 840
    frame #22: 0x0000000103bce27c libleanshared.dylib`l_Lean_profileitIOUnsafe___rarg___lambda__1 + 24
    frame #23: 0x0000000103bce4ec libleanshared.dylib`l_Lean_profileitIOUnsafe___rarg___lambda__1___boxed + 20
    frame #24: 0x00000001066f10bc libleanshared.dylib`lean_apply_1 + 528
    frame #25: 0x0000000106644260 libleanshared.dylib`lean_profileit + 128
    frame #26: 0x0000000103bce3e0 libleanshared.dylib`l_Lean_profileitIOUnsafe___rarg + 112
    frame #27: 0x00000001055d564c libleanshared.dylib`l___private_Lean_Elab_Term_0__Lean_Elab_Term_applyAttributesCore + 268
    frame #28: 0x00000001055d6264 libleanshared.dylib`l_Lean_Elab_Term_applyAttributes + 52
    frame #29: 0x000000010597b840 libleanshared.dylib`l_Array_forInUnsafe_loop___at_Lean_Elab_Command_elabAttr___spec__6___lambda__1 + 740
    frame #30: 0x000000010597daf4 libleanshared.dylib`l_Array_forInUnsafe_loop___at_Lean_Elab_Command_elabAttr___spec__6___lambda__1___boxed + 124
    frame #31: 0x00000001066f65d8 libleanshared.dylib`lean_apply_8 + 1252
    frame #32: 0x00000001066f5b6c libleanshared.dylib`lean_apply_7 + 1252
    frame #33: 0x0000000104f587b0 libleanshared.dylib`l___private_Lean_Elab_InfoTree_Main_0__Lean_Elab_withSavedPartialInfoContext___at_Lean_Elab_Command_liftTermElabM___spec__2___rarg___lambda__1 + 344
    frame #34: 0x0000000104f59ec4 libleanshared.dylib`l___private_Lean_Elab_InfoTree_Main_0__Lean_Elab_withSavedPartialInfoContext___at_Lean_Elab_Command_liftTermElabM___spec__2___rarg + 280
    frame #35: 0x0000000104f5af20 libleanshared.dylib`l_Lean_Elab_Command_liftTermElabM___rarg___lambda__1 + 144
    frame #36: 0x00000001066f5ab8 libleanshared.dylib`lean_apply_7 + 1072
    frame #37: 0x0000000105636090 libleanshared.dylib`l_Lean_Elab_Term_TermElabM_run___rarg + 844
    frame #38: 0x0000000104f5b8fc libleanshared.dylib`l_Lean_Elab_Command_liftTermElabM___rarg + 1696
    frame #39: 0x000000010597d67c libleanshared.dylib`l_Array_forInUnsafe_loop___at_Lean_Elab_Command_elabAttr___spec__6 + 928
    frame #40: 0x000000010597de60 libleanshared.dylib`l_Lean_Elab_Command_elabAttr + 772
    frame #41: 0x000000010597e838 libleanshared.dylib`l_Lean_Elab_Command_elabAttr___boxed + 20
    frame #42: 0x00000001066f2cd4 libleanshared.dylib`lean_apply_3 + 868
    frame #43: 0x0000000104f385f8 libleanshared.dylib`l_Lean_Elab_withInfoTreeContext___at___private_Lean_Elab_Command_0__Lean_Elab_Command_elabCommandUsing___spec__2 + 396
    frame #44: 0x0000000104f39e48 libleanshared.dylib`l___private_Lean_Elab_Command_0__Lean_Elab_Command_elabCommandUsing + 484
    frame #45: 0x00000001066f2cf0 libleanshared.dylib`lean_apply_3 + 896
    frame #46: 0x0000000104f341d4 libleanshared.dylib`l_Lean_withTraceNode___at_Lean_Elab_Command_runLinters___spec__11 + 788
    frame #47: 0x00000001066f2d54 libleanshared.dylib`lean_apply_3 + 996
    frame #48: 0x00000001066f2cf0 libleanshared.dylib`lean_apply_3 + 896
    frame #49: 0x0000000104f40e30 libleanshared.dylib`l_Lean_Elab_withLogging___at_Lean_Elab_Command_elabCommand___spec__2 + 104
    frame #50: 0x0000000104f4c51c libleanshared.dylib`l_Lean_Elab_Command_elabCommandTopLevel___lambda__1 + 432
    frame #51: 0x00000001066f10e8 libleanshared.dylib`lean_apply_1 + 572
    frame #52: 0x0000000103bce27c libleanshared.dylib`l_Lean_profileitIOUnsafe___rarg___lambda__1 + 24
    frame #53: 0x0000000103bce4ec libleanshared.dylib`l_Lean_profileitIOUnsafe___rarg___lambda__1___boxed + 20
    frame #54: 0x00000001066f10bc libleanshared.dylib`lean_apply_1 + 528
    frame #55: 0x0000000106644260 libleanshared.dylib`lean_profileit + 128
    frame #56: 0x0000000103bce3e0 libleanshared.dylib`l_Lean_profileitIOUnsafe___rarg + 112
    frame #57: 0x0000000104f4fce0 libleanshared.dylib`l_Lean_Elab_Command_elabCommandTopLevel + 1284
    frame #58: 0x00000001057d2f30 libleanshared.dylib`l_Lean_Elab_Frontend_elabCommandAtFrontend + 1384
    frame #59: 0x00000001057d63b8 libleanshared.dylib`l_Lean_Elab_Frontend_processCommand + 1332
    frame #60: 0x00000001057d6e48 libleanshared.dylib`l_Lean_Elab_Frontend_processCommands + 72
    frame #61: 0x00000001057d7248 libleanshared.dylib`l_Lean_Elab_IO_processCommands + 212
    frame #62: 0x00000001057d83d0 libleanshared.dylib`l_Lean_Elab_runFrontend___lambda__3 + 76
    frame #63: 0x00000001057d96d0 libleanshared.dylib`lean_run_frontend + 2436
    frame #64: 0x00000001065e72b4 libleanshared.dylib`lean::run_new_frontend(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&, lean::options const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>> const&, lean::name const&, unsigned int, lean::optional<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>> const&, unsigned char) + 244
    frame #65: 0x00000001065e9c8c libleanshared.dylib`lean_main + 8348
    frame #66: 0x0000000184f93f28 dyld`start + 2236
```

cc @Kha
2024-04-29 10:58:11 +00:00
Leonardo de Moura
15cfe60640 test: for flexible reducibility attributes 2024-04-29 05:46:11 +02:00
Leonardo de Moura
7294646eb9 chore: update stage0 2024-04-29 05:46:11 +02:00
Leonardo de Moura
47a34316fc feat: flexible reducibility attributes
- We can set `[irreducible]`, `[semireducible]`, and `[reducible]` for
imported declarations.
- Support for `scoped` and `local` versions

TODO: discuss whether we need all this power after we add the module
system.
2024-04-29 05:46:11 +02:00
Leonardo de Moura
5a5a77dd44 feat: set_option diag true tracks recursor reduction (#4020) 2024-04-29 02:06:14 +00:00
Leonardo de Moura
5e30638725 feat: set_option diag true tracks how many times an instance is used (#4019) 2024-04-29 01:05:00 +00:00
Leonardo de Moura
dc442ec137 fix: theorems should never be marked as extern (#4018) 2024-04-29 00:01:49 +00:00
Leonardo de Moura
9d14c0456b feat: add set_option diag true for diagnostic counters (#4016)
It currently only reports how many times each declaration has been
unfolded, and how often the `isDefEq` heuristic for `f a =?= f b` has
been used. Only counters above the threshold are reported.
2024-04-28 22:14:08 +00:00
Joachim Breitner
bb1a373420 fix: subst notation (heq ▸ h) should fail if it does't subst (#3994)
The subst notation substitues in the expected type, if present, or in
the type of the argument, if no expected type is known.

If there is an expected type it already fails if it cannot find the
equations' left hand side or right hand side. But if the expected type
is not known and the equation's lhs is not present in the second
argument's type, it will happily do a no-op-substitution.

This is inconsistent and unlikely what the user intended to do, so we
now print an error message now.

This still only looks for the lhs; search for the rhs as well seems
prudent, but I’ll leave that for a separate PR, to better diagnose the
impact on mathlib.

This triggers a small number of pointless uses of subst in mathlib, see
https://github.com/leanprover-community/mathlib4/pull/12451
2024-04-28 20:29:04 +00:00
Joachim Breitner
f817d5a706 feat: use structural recursion in Fin.induction (#4010)
this should help with reducing mathlib's vector notation (`![a,b,c] 2`),
and reduce fallout from #4002
2024-04-28 20:28:41 +00:00
Leonardo de Moura
adc4c6a7cf chore: add backward compatibility flags for recent isDefEq changes (#4012) 2024-04-28 17:30:49 +00:00
Leonardo de Moura
b8b6b219c3 chore: move trace.cpp to kernel (#4014)
Motivation: trace kernel `is_def_eq`
2024-04-28 17:24:48 +00:00
Leonardo de Moura
63067d0d34 chore: code convention (#4009) 2024-04-28 15:49:55 +00:00
Leonardo de Moura
3be22538d2 chore: add backward compatibility option for TC optimization (#4008) 2024-04-28 06:04:06 +00:00
Leonardo de Moura
99e8270d2d fix: proposition fields must be theorems (#4006)
closes #2575
2024-04-28 01:59:47 +00:00
Leonardo de Moura
8fa36c7730 fix: match_expr parser (#4007)
closes #3989
closes #3990
2024-04-27 23:56:28 +00:00
Leonardo de Moura
a359586a96 perf: isDefEqProj (#4004)
Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-04-27 23:30:35 +00:00
Leonardo de Moura
e3592e40cf chore: remove dead code at Structure.lean (#4005) 2024-04-27 23:10:28 +00:00
Sebastian Ullrich
7b0d4610b0 chore: CI: pin macos-13 (#3992)
macos-latest changed to arm64. It should not be hard to switch our setup
to cross-compiling x64 instead of arm64 but let's get master green again
first.
2024-04-27 20:58:22 +00:00
Leonardo de Moura
917a31f694 perf: consider at most one answer for type class resolution subgoals not containing metavariables
closes #3996
2024-04-27 21:12:19 +02:00
Leonardo de Moura
34a788110f chore: code convention 2024-04-27 21:12:19 +02:00
Leonardo de Moura
ce350f3481 perf: linearity issue 2024-04-27 21:12:19 +02:00
Leonardo de Moura
1630d9b803 feat: universe constraint approximations (#3981)
We add a new configuration flag for `isDefEq`:
`Meta.Config.univApprox`.
When it is true, we approximate the solution for universe constraints
such as
- `u =?= max u ?v`, we use `?v := u`, and ignore the solution `?v := 0`.
- `max u v =?= max u ?w`, we use `?w := v`, and ignore the solution `?w
:= max u v`.

We only apply these approximations when there the contraints cannot be
postponed anymore. These approximations prevent error messages such as
```
error: stuck at solving universe constraint
  max u ?u.3430 =?= u
```
This kind of error seems to appear in several Mathlib files.

We currently do not use these approximations while synthesizing type
class instances.
2024-04-24 20:27:51 +00:00
Sebastian Ullrich
605cecdde3 fix: show trace timings in infoview (#3985)
A regression introduced by #3801
2024-04-24 15:55:27 +00:00
Kyle Miller
a9db0d2e53 fix: use Name.appendCore instead of Name.append in unresolveNameGlobal (#3946)
`Name.append` has special handling of macro scopes, and it would cause
`unresolveNameGlobal` to panic. Using `Name.appendCore` to append name
parts is justified by the fact that it's being used to reassemble a
disassembled name.

Closes #2291
2024-04-24 15:07:18 +00:00
Kyle Miller
158979380e feat: make Level -> MessageData coercion respect pp.mvars (#3980)
Adds `ppLevel` to the `PPFns` extension so that the coercion can pass
the pretty printing context (including the `pp.mvars` option setting) to
the `Level` formatter.
2024-04-24 14:23:42 +00:00
Joachim Breitner
f9f278266e chore: ci to set “changes-stage0” label (#3979)
Expands on #3971 to do something useful even before the PR enters the
queue:

If stage0 changes are detected in the PR, set the changes-stage0 label
(which
has a tooltip to explain what this entail), and also remove the label if
it no
longer applies.
2024-04-24 07:08:34 +00:00
Austin Letson
861a92a06d doc: docstrings for List.rotateRight/Left and example for List.partitionM (#3919)
Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-04-24 06:15:05 +00:00
Markus Himmel
f4ae6fc8aa fix: add instances to make ac_rfl work out of the box (#3942)
Previously the `ac_rfl` tactic was only really usable when depending on
mathlib. With these instances, `ac_rfl` can deal with the various
operations defined in Lean.

---------

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-04-24 06:12:36 +00:00
Kim Morrison
f2a54ec0eb feat: script to summarize issues (#3952) 2024-04-24 06:11:07 +00:00
Sebastian Ullrich
22a581f38d chore: update code owners 2024-04-24 10:16:16 +02:00
Kim Morrison
706a4cfd73 feat: monadic generalization of FindExpr (#3970)
Not certain this is a good idea. Motivated by code duplication
introduced in #3398.
2024-04-24 06:07:54 +00:00
Richard Copley
4fe0259354 feat: exact?%: do not report suggestions which do not close the goal (#3974)
This makes `exact?%` behave like `by exact?` rather than `by apply?`.

If the underlying function `librarySearch` finds a suggestion which
closes the goal, use it (and add a code action). Otherwise log an error
and use `sorry`. The error is either
```text
`exact?%` didn't find any relevant lemmas
```
or
```text
`exact?%` could not close the goal. Try `by apply` to see partial suggestions.
```

---


[Zulip](https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/Useful.20term.20elaborators/near/434863856)

---------

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-04-24 06:07:11 +00:00
Kim Morrison
41697dcf6c feat: improvements to test_extern command (#3075)
Two improvements
[suggested](https://github.com/leanprover/lean4/pull/2970#issuecomment-1853436906)
by @digama0 after the initial PR was merged.

* Allow testing `implemented_by` attributes as well.
* Use `DecidableEq` rather than `BEq` for stricter testing.
2024-04-24 03:56:16 +00:00
Kim Morrison
3990a9b3be chore: upstream Std material from Data/List|Array/Init (#3975)
See proposal on
[zulip](https://leanprover.zulipchat.com/#narrow/stream/348111-std4/topic/upstreaming.20of.20List.2FArray.20material/near/434879041);
I won't merge this until there's a chance for discussion there.
2024-04-24 03:23:25 +00:00
François G. Dorais
05b68687c0 feat: #print command shows structure fields (#3768)
<!--
# Read this section before submitting

* Ensure your PR follows the [External Contribution
Guidelines](https://github.com/leanprover/lean4/blob/master/CONTRIBUTING.md).
* Please make sure the PR has excellent documentation and tests. If we
label it `missing documentation` or `missing tests` then it needs
fixing!
* Include the link to your `RFC` or `bug` issue in the description.
* If the issue does not already have approval from a developer, submit
the PR as draft.
* The PR title/description will become the commit message. Keep it
up-to-date as the PR evolves.
* If you rebase your PR onto `nightly-with-mathlib` then CI will test
Mathlib against your PR.
* You can manage the `awaiting-review`, `awaiting-author`, and `WIP`
labels yourself, by writing a comment containing one of these labels on
its own line.
* Remove this section, up to and including the `---` before submitting.
-->
See RFC #3644 for a discussion of design choices.

Closes #3644
2024-04-24 03:18:09 +00:00
Kyle Miller
94360a72b3 feat: make pp.mvars false pretty print universe mvars as _ (#3978)
Suggestion on
[Zulip](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/.23guard_msgs.20variant.3A.20don't.20care.20about.20whitespace/near/434906526)
2024-04-23 20:34:48 +00:00
Kim Morrison
fb135b8cfe fix: improve isDefEqProj (#3977)
Currently this will fail in two tests, because of changes in #3965.

* Sometimes we need to add an additional universe annotation, or we get
a `stuck at solving universe constraint max u ?u =?= u`.
* Sometimes we need to specify arguments that could previously be found
by unification.

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-04-23 18:09:26 +00:00
Mario Carneiro
4f664fb3b5 feat: improve @[deprecated] attr (#3968)
Complement to #3967 , adds a `(since := "<date>")` field to
`@[deprecated]` so that metaprogramming code has access to the
deprecation date for e.g. bulk removals. Also adds `@[deprecated
"deprecation message"]` to optionally replace the default text
"`{declName}` has been deprecated, use `{newName}` instead".
2024-04-23 17:00:32 +00:00
Mac Malone
7a076d0bd4 fix: lake: package duplication in workspace (#3957)
Fixes a bug where packages that appeared multiple times in the
dependency tree would be duplicated in the workspace (and in manifests).
Added a regression test for this to prevent this from happening again in
the future.

This was first reported in
l[eanprover/mathlib4#12250](https://github.com/leanprover-community/mathlib4/pull/12258#discussion_r1571834509).
2024-04-23 09:50:10 +00:00
Joachim Breitner
f40c51f346 chore: prevent stage0 changes via the merge queue (#3971)
these need manual rebase merges by an admin, so lets prevent accidential
merges via the squashing merge queue.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-04-23 09:47:27 +00:00
Leonardo de Moura
b2de43ed88 fix: simp caching (#3972)
closes #3943

TODO: remove `cache` field from `Simp.Result`.
2024-04-22 21:22:42 +00:00
Mac Malone
d95e741824 feat: lean CLI option to print messages as JSON (#3939)
Adds a `--json` option to the `lean` CLI. When used, the Lean frontend
will print messages as JSON objects using the default `ToJson` encoding
for the `Message` structure. This allows consumers (such as Lake) to
handle Lean output in a more intelligent, well-structured way.

`Message` has been refactored into `BaseMessage`, `Message`, and
`SerialMessage` to enable deriving `ToJson`/ `FromJson` instances
automatically for `BaseMessage` / `SerialMessage`. `SerialMessage` is a
`Message` with its `MessageData` eagerly serialized to a `String`.
2024-04-22 15:45:32 +00:00
Mario Carneiro
70a23945bf feat: add model implementation for UTF8 enc/dec (#3961)
- [x] Depends on: #3958 
- [x] Depends on: #3960

This makes the UTF-8 encode and decode functions have lean definitions,
so that we can prove properties about them downstream.
2024-04-22 10:24:53 +00:00
Kim Morrison
7c34b736fc chore: deprecate Option.toBool in favour of Option.isSome (#3866) 2024-04-22 07:20:19 +00:00
Sebastian Ullrich
7a65bde3e3 doc: Command.set_option (#3872)
Co-authored-by: Kim Morrison <kim@tqft.net>
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-04-22 07:18:17 +00:00
Kim Morrison
22ce2fea9b chore: fix Util.Heartbeats module-doc (#3954) 2024-04-22 07:02:58 +00:00
Joachim Breitner
ea23ab6fef refactor: make throwTacticEx parameter msg optional (#3951)
previously, the empty `MessageData` (`m!""`) was used to indicate “no
message”, and `throwTacticEx` would format the message differently then.
But the semantics of `MessageData.isEmpty` isn't entirely clear in the
presence of lazy message data (e.g. `.ofPPFormat`).

So to avoid wondering what `isEmpty` should do there, let's simply use
an optional argument to `throwTacticEx` and get rid of
`MessageData.isEmpty`.
2024-04-22 06:55:41 +00:00
Mario Carneiro
e437bfece9 chore: use compareLex in lexOrd (#3882)
This reduces the number of reimplemented functions which complicate
proofs. After inlining it ends up the same as before.

`ltOfOrd` is also changed to use `compare a b = .lt` instead of
`(compare a b == .lt) = true`, for consistency with the normal form in
std.
2024-04-22 06:48:44 +00:00
Sebastian Ullrich
5e313e98d0 doc: Classical.choice (#3871)
Co-authored-by: Mario Carneiro <di.gama@gmail.com>
2024-04-22 06:36:56 +00:00
Kyle Miller
46f42cc9ba doc: update norm_cast and push_cast documentation (#3908)
Co-authored-by: Mario Carneiro <di.gama@gmail.com>
2024-04-22 05:28:25 +00:00
Sebastian Ullrich
7400a40116 doc: section/namespace/end (#3873)
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
Co-authored-by: Mario Carneiro <di.gama@gmail.com>
2024-04-22 05:23:00 +00:00
Kyle Miller
41d310ab39 fix: solveByElim would add symm hypotheses to local context and make impossible-to-elaborate terms (#3962)
Rather than adding symm hypotheses to the local context, it now adds
them to the list of hypotheses derived from the local context.

This is not ideal for performance reasons, but it at least closes #3922.

In the future, solveByElim could maintain its own cache of facts that it
updates whenever it does intro.
2024-04-22 04:13:22 +00:00
Arthur Adjedj
6ad28ca446 feat: add inductive.autoPromoteIndices option (#3590)
This PR partly addresses #3458, by adding an option `autoPromoteIndices`
to turn off the promotion of fixed indices to parameters. The actual fix
for the issue is in a separate PR #3591.

Because nested inductive datatypes parameters cannot contain local
variables, it is often desirable for a fixed index to not be promoted,
as to allow free variables in that place. See example in `3458_1.lean`
2024-04-22 03:42:22 +00:00
Henrik Böving
263c93aac8 perf: ensure linearity in Parsec.many*Core (#3830) 2024-04-22 03:41:06 +00:00
Leonardo de Moura
e4daca8d6b chore: remove dead code at kernel compare (#3966) 2024-04-22 00:54:24 +00:00
Leonardo de Moura
3dd398a8a4 perf: improve isDefEq for contraints of the form t.i =?= s.i (#3965)
We now use lazy delta reduction at `t` and `s`.
See new test for motivation.
2024-04-22 00:41:34 +00:00
Kim Morrison
ac0f699775 perf: improve heuristic at isDefEq (#3837)
This is intended to fail at present: it just adds a test case containing
a minimization of a Mathlib slowdown from #3807.

Prior to #3807, the declaration `exists_algHom_adjoin_of_splits'''` at
the end of the file would take around 16,000 heartbeats. Now it takes
around 210,000 heartbeats.

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-04-21 23:27:44 +00:00
Leonardo de Moura
69202d9b73 fix: ReducibilityHints.lt (#3964) 2024-04-21 21:44:18 +00:00
Mario Carneiro
62cdb51ed5 feat: UTF-8 string validation (#3958)
Previously, there was a function `opaque fromUTF8Unchecked : ByteArray
-> String` which would convert a list of bytes into a string, but as the
name implies it does not validate that the string is UTF-8 before doing
so and as a result it produces unsound results in the compiler (because
the lean model of `String` indirectly asserts UTF-8 validity). This PR
replaces that function by
```lean
opaque validateUTF8 (a : @& ByteArray) : Bool

opaque fromUTF8 (a : @& ByteArray) (h : validateUTF8 a) : String
```
so that while the function is still "unchecked", we have a proof witness
that the string is valid. To recover the original, actually unchecked
version, use `lcProof` or other unsafe methods to produce the proof
witness.

Because this was the only `ByteArray -> String` conversion function, it
was used in several places in an unsound way (e.g. reading untrusted
input from IO and treating it as UTF-8). These have been replaced by
`fromUTF8?` or `fromUTF8!` as appropriate.
2024-04-20 18:36:37 +00:00
Mario Carneiro
5eb274d486 fix: don't use modulo for UInt upcasting (#3960)
This makes `(v : UInt8).toUInt16.toNat = (v : UInt8).toNat` a defeq,
which simplifies proofs.
2024-04-20 16:37:02 +00:00
Mario Carneiro
aeacb7b69e feat: String.Pos.isValid (#3959)
This adds a function that can be used to check whether a position is on
a UTF-8 byte boundary.
2024-04-20 14:57:35 +00:00
Lean stage0 autoupdater
291bb84c97 chore: update stage0 2024-04-19 14:31:23 +00:00
Mario Carneiro
3c36020d13 feat: @[builtin_doc] attribute (part 1) (#3953)
First part of #3918.
2024-04-19 12:21:10 +00:00
Kim Morrison
f23be4a964 feat: upstream false_or_by_contra tests (2nd attempt) (#3949) 2024-04-19 08:09:50 +00:00
Kim Morrison
c5ff671b8a chore: update Authors: line in BitVec files (#3948) 2024-04-19 08:07:25 +00:00
Lean stage0 autoupdater
9dcf07203e chore: update stage0 2024-04-19 08:22:54 +00:00
Kim Morrison
d6474135ba feat: upstream false_or_by_contra tests (#3947)
And fix broken `builtin_tactic` attribute.
2024-04-19 05:30:51 +00:00
Kim Morrison
d1a42aae2a chore: remove @ from rw? suggestions, and enable hover on constants in #check (#3911)
* Replaces the unused `Lean.PrettyPrinter.ppConst` with
`MessageData.ofConst` (which similarly avoids an unnecessary `@`) and
that further generates a hover for the constant

* Uses this in `TryThis.addRewriteSuggestion`, so that `rw?` suggestions
don't have unnecessary `@`s.

* Add `MessageData.signature`, as a wrapper around
`PrettyPrinter.signature`, using the same machinery to generate hovers
for constants, improving the hover behaviour in #check so that we get
second order pop-up for constants in the signature. (Not sure how to
write tests for second order hovers, so there is no test for this.)
2024-04-19 01:27:02 +00:00
David Thrane Christiansen
b6d77be6a5 feat: show diffs when #guard_msgs fails (#3912)
Adds the ability to show a diff when `guard_msgs` fails, using the
histogram diff algorithm pioneered in jgit. This algorithm tends to
produce more user-friendly diffs, but it can be quadratic in the worst
case. Empirically, the quadratic case of this implementation doesn't
seem to be slow enough to matter for messages smaller than hundreds of
megabytes, but if it's ever a problem, we can mitigate it the same way
jgit does by falling back to Myers diff.

See lean/run/guard_msgs.lean in the tests directory for some examples of
its output.
2024-04-18 15:09:44 +00:00
Mac Malone
0c9f9ab37a feat: isTty (#3930)
Adds `IO.FS.Handle.isTty` to check whether a handle is a Windows console
or Unix terminal. Also adds an `isTty` field to `IO.FS.Stream`, so that
this can be checked on, e.g., `stdout`.
2024-04-18 08:50:43 +00:00
Mario Carneiro
df1e6ba7fe fix: built-in parser attributes link to the wrong place (#3916)
Go-to-def on `@[builtin_term_parser]` should go to the line
```lean
builtin_initialize registerBuiltinParserAttribute `builtin_term_parser ``Category.term
```
not
```lean
/-- `term` is the builtin syntax category for terms. ... -/
def term : Category := {}
```
2024-04-18 08:28:16 +00:00
Marc Huisinga
faa4d16dc1 fix: semantic tokens performance (#3932)
While implementing #3925, I noticed that the performance of the
`textDocument/semanticTokens/full` request is *extremely* bad due to a
quadratic implementation. Specifically, on my machine, computing the
full semantic tokens for `Lean/Elab/Do.lean` took a full 5s. In
practice, this means that while elaborating the file, one core is
entirely busy with computing the semantic tokens for the file.

This PR fixes this performance bug by re-implementing the semantic token
handling, reducing the latency for `Lean/Elab/Do.lean` from 5s to 60ms.
As a result, the overly cautious refresh latency of 5s in #3925 can
easily be reduced to 2s again.

Since the previous semantic tokens implementation used a very brittle
hack to identify projections, this PR also changes the projection
notation elaboration to augment the `InfoTree` syntax for the field of a
projection with a special syntax node of kind
`Lean.Parser.Term.identProjKind`. With this syntax kind, projection
fields can now easily be identified in the `InfoTree`.
2024-04-18 07:48:44 +00:00
Henrik Böving
11ff00439e feat: make linter options more explicitly discoverable (#3938)
Closes #3937
2024-04-18 07:20:55 +00:00
Kyle Miller
319940da77 feat: make anonymous instance names not include proofs (#3934) 2024-04-17 19:41:34 +00:00
Lean stage0 autoupdater
11a9d2ee4b chore: update stage0 2024-04-17 19:26:22 +00:00
Joachim Breitner
504336822f perf: faster Nat.repr implementation in C (#3876)
`Nat.repr` was implemented by generating a list of `Chars`, each created
by a 10-way if-then-else. This can cause significant slow down in some
particular use cases.

Now `Nat.repr` is `implemented_by` a faster implementation that uses
C++’s `std::to_string` on small numbers (< USize.size) and maintains an
array of pre-allocated strings for the first 128 numbers.

The handling of big numbers (≥ USize.size) remains as before.
2024-04-17 18:11:05 +00:00
Joachim Breitner
4f50544242 chore: Nat.repr microbenchmark (#3888) 2024-04-17 18:10:32 +00:00
Kyle Miller
627a0f308b fix: add unused variables ignore function for #guard_msgs (#3931)
The `#guard_msgs` command already runs linters by virtue of using
`elabCommandTopLevel`, so linters should *not* be run on `#guard_msgs`
itself. While we could use a more general solution, of the linters the
unused variables linter is the noisiest one, and it's easy enough to
make it not report messages for `#guard_msgs`.
2024-04-17 15:30:17 +00:00
Kyle Miller
89558a007b doc: docstrings on binder types, make sure hovers work (#3917)
Moved `ppGroup` inside the `leading_parser`s for all the binder types so
that hovering works. Improved the docstrings.
2024-04-17 14:21:34 +00:00
Kyle Miller
036b5381f0 fix: make tests be aware of new instance names (#3936)
#3089 caused the stage0 update to cause a number of tests to start
failing because they were using the old instance names.
2024-04-17 16:14:51 +02:00
Lean stage0 autoupdater
88ee503f02 chore: update stage0 2024-04-17 09:21:10 +00:00
Markus Himmel
2397a870f2 feat: add lemma Int.add_bmod (#3890)
Just a lemma that we noticed is missing when working on #3880 at the
retreat. We also noticed that there are naming inconsistencies in the
lemmas for `bmod` and `emod`, we should fix that in the future.
2024-04-17 06:13:22 +00:00
Markus Himmel
d3e004932c chore: move docstrings for open, variable, universe, export from elaborator to parser (#3891)
During the documentation sprint we discussed that user-visible
documentation for syntax should generally go on the parser instead of
the elaborator.
2024-04-17 06:13:11 +00:00
Kim Morrison
cefba8abd2 chore: rename Option.toMonad and remove argument (#3865) 2024-04-17 04:58:54 +00:00
Kim Morrison
c6fbeaa721 doc: add doc-string for LawfulMonad/Applicative (#3859)
Co-authored-by: Mario Carneiro <di.gama@gmail.com>
2024-04-17 04:54:36 +00:00
David Thrane Christiansen
85e7000666 doc: update release checklist based on experience with 4.7.0 (#3833)
@semorrison, does this include all the answers to the questions I asked
in our thread? I think so!

---------

Co-authored-by: Mac Malone <tydeu@hatpress.net>
2024-04-17 04:33:45 +00:00
Kyle Miller
75e68e7565 doc: fix docstring for Lean.Meta.mkEqOfHEq (#3921) 2024-04-16 16:33:12 +00:00
Marc Huisinga
c51e4f57bd fix: do not send as many semantic token refresh requests (#3925)
Fixes #3879.

Making semantic token requests fast is still in progress.
2024-04-16 16:32:57 +00:00
Sebastian Ullrich
ac4b5089a3 chore: bring back tactic cache while incrementality is in-development (#3924) 2024-04-16 15:42:30 +00:00
Joachim Breitner
784972462a feat: omega: more helpful error messages (#3847)
while trying to help a user who was facing an unhelpful
```
omega did not find a contradiction:
[0, 0, 0, 0, 1, -1] ∈ [1, ∞)
[0, 0, 0, 0, 0, 1] ∈ [0, ∞)
[0, 0, 0, 0, 1] ∈ [0, ∞)
[1, -1] ∈ [1, ∞)
[0, 0, 0, 1] ∈ [0, ∞)
[0, 1] ∈ [0, ∞)
[1] ∈ [0, ∞)
[0, 0, 0, 1, 1] ∈ [-1, ∞)
```
I couldn’t resist and wrote a pretty-printer for these problem that
shows the linear combination as such, and includes the recognized atoms.
This is especially useful since oftem `omega` failures stem from failure
to recognize atoms as equal. In this case, we now get:

```
omega-failure.lean:19:2-19:7: error: omega could not prove the goal:
a possible counterexample may satisfy the constraints
  d - e ≥ 1
  e ≥ 0
  d ≥ 0
  a - b ≥ 1
  c ≥ 0
  b ≥ 0
  a ≥ 0
  c + d ≥ -1
where
 a := ↑(sizeOf xs)
 b := ↑(sizeOf x)
 c := ↑(sizeOf x.fst)
 d := ↑(sizeOf x.snd)
 e := ↑(sizeOf xs)
```
and this might help the user make progress (e.g. by using `case x`
first, and investingating why `sizeOf xs` shows up twice)
2024-04-16 15:11:51 +00:00
Sebastian Ullrich
535427ada4 feat: basic incrementality API (#3849)
The fundamentals of #3636
2024-04-16 12:26:28 +00:00
Joachim Breitner
c0fbcc76c4 feat: FunInd: reserve name .mutual_induct (#3898) 2024-04-16 11:59:40 +00:00
Joachim Breitner
ea910794fa doc: crosslink {realize,resolve}GlobalName[NoOverload]?[WithInfo]?, (#3897)
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-04-16 11:59:22 +00:00
Kim Morrison
a8df7d9d5c fix: find nightly-with-mathlib SHA (#3923) 2024-04-16 11:18:51 +00:00
Joachim Breitner
23aacdeac0 doc: instantiateMVars (#3862)
(unclear if the example is worth the hover space here)
2024-04-15 14:02:40 +00:00
Kim Morrison
62bb0f662b doc: add docstring to add_decl_doc (#3863)
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-04-15 12:51:38 +00:00
Joachim Breitner
822890ad27 doc: docstrings for Alternative (#3860)
Co-authored-by: Mario Carneiro <di.gama@gmail.com>
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-04-15 12:40:40 +00:00
Joachim Breitner
3b0c101792 doc: docstrings for List.head/tail/getLast variants (#3864)
Co-authored-by: Mario Carneiro <di.gama@gmail.com>
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-04-15 12:40:38 +00:00
Sebastian Ullrich
2dcd42f395 feat: trace.profiler export to Firefox Profiler (#3801)
Reusing the best profiling UI out there

Usage:
```
lean -Dtrace.profiler=true -Dtrace.profiler.output=profile.json foo.lean ...
```
then open `profile.json` in https://profiler.firefox.com/.

See also `script/collideProfiles.lean` for minimizing and merging
profiles.
2024-04-15 12:13:14 +00:00
Sebastian Ullrich
6712913bfe chore: update cross-bench setup 2024-04-15 10:59:07 +02:00
Kyle Miller
1c20b53419 feat: shorten auto-generated instance names (#3089)
Implements a new method to generate instance names for anonymous
instances that uses a heuristic that tends to produce shorter names. A
design goal is to make them relatively unique within projects and
definitely unique across projects, while also using accessible names so
that they can be referred to as needed, both in Lean code and in
discussions.

The new method also takes into account binders provided to the instance,
and it adds project-based suffixes. Despite this, a median new name is
73% its original auto-generated length. (Compare: [old generated
names](https://gist.github.com/kmill/b72bb43f5b01dafef41eb1d2e57a8237)
and [new generated
names](https://gist.github.com/kmill/393acc82e7a8d67fc7387829f4ed547e).)

Some notes:
* The naming is sensitive to what is explicitly provided as a binder vs
what is provided via a `variable`. It does not make use of `variable`s
since, when names are generated, it is not yet known which variables are
used in the body of the instance.
* If the instance name refers to declarations in the current "project"
(given by the root module), then it does not add a suffix. Otherwise, it
adds the project name as a suffix to protect against cross-project
collisions.
* `set_option trace.Elab.instance.mkInstanceName true` can be used to
see what name the auto-generator would give, even if the instance
already has an explicit name.

There were a number of instances that were referred to explicitly in
meta code, and these have been given explicit names.

Removes the unused `Lean.Elab.mkFreshInstanceName` along with the
Command state's `nextInstIdx`.

Fixes #2343
2024-04-13 18:08:50 +00:00
Kyle Miller
40df539ef1 doc: update RELEASES for rcases using the custom Nat eliminator (#3902)
Note for #3747.
2024-04-13 17:56:06 +00:00
Kyle Miller
c4bfe25d18 feat: make rcases use the custom Nat eliminator (#3747)
As a special case, makes the `rcases` machinery use `Nat.casesAuxOn` so
that goal states see `0` and `n + 1` rather than `Nat.zero` and
`Nat.succ n`. This is a followup to enabling custom eliminators for
`cases` and `induction`.

This doesn't use custom eliminators in general since `rcases` uses
`Lean.MVarId.cases`, which is completely different from what `cases` and
`induction` use.
2024-04-13 16:55:48 +00:00
Kyle Miller
3d24c68347 doc: rephrase a couple RELEASES entries (#3900) 2024-04-13 16:54:57 +00:00
Lean stage0 autoupdater
b0a305f19f chore: update stage0 2024-04-13 09:49:19 +00:00
Kyle Miller
eef928b98d feat: whitespace and message ordering configurations for #guard_msgs (#3883)
Adds options to control whitespace normalization and message ordering in
`#guard_msgs`.

Examples:
1. `#guard_msgs (whitespace := lax)` ignores differences in whitespace
completely.
2. `#guard_msgs (whitespace := exact)` requires an exact match for
whitespace (after trimming).
3. `#guard_msgs (ordering := sorted)` sorts the list of messages, to
make it insensitive to message order.
2024-04-13 08:53:43 +00:00
Joachim Breitner
9eeecb6d32 doc: docstrings for List.mapM and friends (#3867)
Co-authored-by: Mario Carneiro <di.gama@gmail.com>
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-04-13 07:57:55 +00:00
Kim Morrison
62747bd293 doc: add docstring for Nat.gcd (#3857) 2024-04-13 07:56:15 +00:00
Kim Morrison
32b9bc47b7 chore: add doc-string for Prod.mk (#3856) 2024-04-13 07:55:20 +00:00
David Thrane Christiansen
864221d433 chore: rename fields of Subarray to follow Lean conventions (#3851)
Co-authored-by: Eric Wieser <wieser.eric@gmail.com>
2024-04-13 07:52:45 +00:00
Joachim Breitner
2e1ef2211c doc: docstrings for some Fin definitions (#3858)
Co-authored-by: Mario Carneiro <di.gama@gmail.com>
2024-04-13 07:52:32 +00:00
Mario Carneiro
fb82428f2d feat: hover / go-to-def for attribute cmd (#3896)
`attribute [attr] foo` was missing a hover on `foo`.
2024-04-13 07:13:25 +00:00
Kyle Miller
c24b419ee4 doc: fix simp configuration option default value for decide (#3894) 2024-04-12 22:02:08 +00:00
Mario Carneiro
ddbdfb954b chore: use Ordering.then in deriving Ord (#3893)
This should improve the performance of the deriving a bit since it
doesn't have to generate so many matchers. The main motivation though is
to make it easier to prove properties about the expression by using more
standard functions. The generated implementation should end up the same,
since `Ordering.then` is `@[macro_inline]`.
2024-04-12 21:09:27 +00:00
Kyle Miller
e59fad2955 doc: describe all simp configuration options (#3870)
Co-authored by Marc Huisinga, with input from Leo.
2024-04-12 16:38:43 +00:00
Henrik Böving
ecba8529cc doc: Leo-Henrik retreat doc (#3869)
Part of the retreat Hackathon.

---------

Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
Co-authored-by: Mario Carneiro <di.gama@gmail.com>
2024-04-12 09:14:31 +00:00
Henrik Böving
723c340a8b perf: fix linearity in (HashSet|HashMap).erase (#3887)
Fixes linearity issues in HashSet/HashMap erase functions.

IR before patch:
```
def Lean.HashMapImp.erase._rarg (x_1 : obj) (x_2 : obj) (x_3 : obj) (x_4 : obj) : obj :=
  let x_5 : obj := proj[0] x_3;
  inc x_5;
  let x_6 : obj := proj[1] x_3;
  inc x_6;
  let x_7 : obj := Array.size  x_6;
  inc x_4;
  let x_8 : obj := app x_2 x_4;
  let x_9 : u64 := unbox x_8;
  dec x_8;
  let x_10 : usize := _private.Lean.Data.HashMap.0.Lean.HashMapImp.mkIdx x_7 x_9 ;
  let x_11 : obj := Array.uget  x_6 x_10 ;
  inc x_11;
  inc x_4;
  inc x_1;
  let x_12 : u8 := Lean.AssocList.contains._rarg x_1 x_4 x_11;
  case x_12 : u8 of
  Bool.false →
    dec x_11;
    dec x_6;
    dec x_5;
    dec x_4;
    dec x_1;
    ret x_3
  Bool.true →
    let x_13 : u8 := isShared x_3;
    case x_13 : u8 of
    Bool.false →
      let x_14 : obj := proj[1] x_3;
      dec x_14;
      let x_15 : obj := proj[0] x_3;
      dec x_15;
      let x_16 : obj := 1;
      let x_17 : obj := Nat.sub x_5 x_16;
      dec x_5;
      let x_18 : obj := Lean.AssocList.erase._rarg x_1 x_4 x_11;
      let x_19 : obj := Array.uset  x_6 x_10 x_18 ;
      set x_3[1] := x_19;
      set x_3[0] := x_17;
      ret x_3
    Bool.true →
      dec x_3;
      let x_20 : obj := 1;
      let x_21 : obj := Nat.sub x_5 x_20;
      dec x_5;
      let x_22 : obj := Lean.AssocList.erase._rarg x_1 x_4 x_11;
      let x_23 : obj := Array.uset  x_6 x_10 x_22 ;
      let x_24 : obj := ctor_0[Lean.HashMapImp.mk] x_21 x_23;
      ret x_24
```

IR after the patch:
```
def Lean.HashMapImp.erase._rarg (x_1 : obj) (x_2 : obj) (x_3 : obj) (x_4 : obj) : obj :=
  let x_5 : u8 := isShared x_3;
  case x_5 : u8 of
  Bool.false →
    let x_6 : obj := proj[0] x_3;
    let x_7 : obj := proj[1] x_3;
    let x_8 : obj := Array.size  x_7;
    inc x_4;
    let x_9 : obj := app x_2 x_4;
    let x_10 : u64 := unbox x_9;
    dec x_9;
    let x_11 : usize := _private.Lean.Data.HashMap.0.Lean.HashMapImp.mkIdx x_8 x_10 ;
    let x_12 : obj := Array.uget  x_7 x_11 ;
    inc x_12;
    inc x_4;
    inc x_1;
    let x_13 : u8 := Lean.AssocList.contains._rarg x_1 x_4 x_12;
    case x_13 : u8 of
    Bool.false →
      dec x_12;
      dec x_4;
      dec x_1;
      ret x_3
    Bool.true →
      let x_14 : obj := 1;
      let x_15 : obj := Nat.sub x_6 x_14;
      dec x_6;
      let x_16 : obj := Lean.AssocList.erase._rarg x_1 x_4 x_12;
      let x_17 : obj := Array.uset  x_7 x_11 x_16 ;
      set x_3[1] := x_17;
      set x_3[0] := x_15;
      ret x_3
  Bool.true →
    let x_18 : obj := proj[0] x_3;
    let x_19 : obj := proj[1] x_3;
    inc x_19;
    inc x_18;
    dec x_3;
    let x_20 : obj := Array.size  x_19;
    inc x_4;
    let x_21 : obj := app x_2 x_4;
    let x_22 : u64 := unbox x_21;
    dec x_21;
    let x_23 : usize := _private.Lean.Data.HashMap.0.Lean.HashMapImp.mkIdx x_20 x_22 ;
    let x_24 : obj := Array.uget  x_19 x_23 ;
    inc x_24;
    inc x_4;
    inc x_1;
    let x_25 : u8 := Lean.AssocList.contains._rarg x_1 x_4 x_24;
    case x_25 : u8 of
    Bool.false →
      dec x_24;
      dec x_4;
      dec x_1;
      let x_26 : obj := ctor_0[Lean.HashMapImp.mk] x_18 x_19;
      ret x_26
    Bool.true →
      let x_27 : obj := 1;
      let x_28 : obj := Nat.sub x_18 x_27;
      dec x_18;
      let x_29 : obj := Lean.AssocList.erase._rarg x_1 x_4 x_24;
      let x_30 : obj := Array.uset  x_19 x_23 x_29 ;
      let x_31 : obj := ctor_0[Lean.HashMapImp.mk] x_28 x_30;
      ret x_31
```

Previously `x_6` (the buckets array) always gets `inc`remented, now only
if the HashMap itself is shared.
2024-04-12 08:54:21 +00:00
Joe Hendrix
2e3d523332 chore: protect Std.BitVec (#3884)
This makes `Std.BitVec` a protected abbreviation so `open Std` doesn't
result in ambiguity errors.
2024-04-12 05:09:46 +00:00
Scott Morrison
cd02ad76f1 doc: doc-string for Ord and Ord.compare (#3861)
Hopefully one day we will be able to do a thorough refactor of the
computable order types in Lean... In the meantime, some doc-strings.
2024-04-11 16:02:33 +00:00
Joe Hendrix
2ba0a4549b feat: add BitVec Int add & mul lemmas (#3880)
This adds some basic lemmas to support commuting ofInt/toInt and
add/mul.

It also removes the simp annotation on `ofNat_add_ofNat` as in some
contexts the other direction or conversion to Int may be desired.
2024-04-11 15:26:45 +00:00
Henrik Böving
3ed2d9b3ad perf: fix linearity issue in insertIfNew (#3881)
This fixes a linearity isssue in `insertIfNew`. As `insertIfNew` is used
in `Lean.finalizeImport` we expect this to improve performance.
2024-04-11 15:12:10 +00:00
Scott Morrison
36f1398aaa doc: some doc-strings for Option (#3868) 2024-04-11 14:27:07 +00:00
Sebastian Ullrich
37938ecde1 doc: moduleDoc (#3874) 2024-04-11 14:21:03 +00:00
Scott Morrison
68e3982eed chore: update CODEOWNERS (#3878)
This adds @digama0 to the CODEOWNERS files for the tactics files which
have recently been upstreamed from Std.
2024-04-11 04:21:42 +00:00
Joachim Breitner
36db040722 refactor: Canonicalizer: run getFunInfo on expression, not key (#3875)
The Canonicalizer creates a “key” expression eliding certain information
(implicit parameters, levels), and `getFunInfo` can be
confused by these terms (in particular, wrong number of level
parameters).

By running `getFunInfo` on the original expression we avoid this, and
can just put `[]` as the level list in the key.
2024-04-10 20:41:15 +00:00
Joachim Breitner
280525f1fc fix: omega: ignore levels in canonicalizer (#3853)
fixes #3848
2024-04-10 08:46:07 +00:00
Joachim Breitner
892bfe2c5f fix: remove unused trace.Elab.syntax option (#3844) 2024-04-08 17:16:24 +00:00
Joe Hendrix
a82f0d9413 fix: offset typeclass checking in simp rules (#3838)
This changes how Nat typeclass checks in offset terms from syntactic
equality to definitional equality with "instances" transparency.

This may have a negative performance penalty in `isOffset?`, but it
should be small in common cases since the relevant instances are small
terms.

This closes #3836
2024-04-07 13:43:59 +00:00
thorimur
182270f8bf fix: typo in withSetOptionIn (#3806)
When using `withSetOptionIn` on syntax `set_option ... in <command>`,
recurse into command syntax (`stx[2]`) instead of the syntax `in`
(`stx[1]`).

---

Demonstration of `stx[1]` vs. `stx[2]`:
```lean
import Lean

def stx := (Lean.Unhygienic.run `(set_option trace.debug true in #print foo)).raw

#eval stx[1] -- Lean.Syntax.atom (Lean.SourceInfo.none) "in"
#eval stx[2] -- `#print` command syntax
```
2024-04-06 18:00:34 +00:00
Scott Morrison
0aa68312b6 chore: when setting up Mathlib CI, make sure nightly-with-mathlib branch has been fetched (#3834)
As reported on
[zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/PR.20release.20failure/near/431281042).
2024-04-05 00:40:50 +00:00
Joe Hendrix
f31c395973 fix: replace unary Nat.succ simp rules with simprocs (#3808)
This removes simp attributes from `Nat.succ.injEq` and
`Nat.succ_sub_succ_eq_sub` to replace them with simprocs. This is
because any reductions involving `Nat.succ` has a high risk of leading
proof performance problems when dealing with even moderately large
numbers.

Here are a couple examples that will both report a maximum recursion
depth error currently. These examples are fixed by this PR.

```
example : (123456: Nat) = 12345667 := by
  simp

example (x : Nat) (p : x = 0) : 1000 - (x + 1000) = 0 := by
  simp
```
2024-04-04 23:15:26 +00:00
Sebastian Ullrich
485baa1b8c chore: update-stage0-commit cmake target (#3692)
Automate creating the commit
2024-04-04 13:35:53 +00:00
Mario Carneiro
e41cd310e9 fix: String.splitOn bug (#3832)
Fixes #3829. As reported on Zulip (both
[recently](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/current.20definition.20of.20.60String.2EsplitOn.60.20is.20incorrect/near/430930535)
and [a year
ago](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/should.20we.20redefine.20.60String.2EsplitOnAux.60.3F/near/365899332)),
`String.splitOn` has a bug when dealing with separators of more than one
character (which are luckily rare). The code change here is very small,
replacing a `i` with `i - j`, but it makes termination more complex so
that's where the rest of the line count goes.
2024-04-04 09:30:53 +00:00
Sebastian Ullrich
d988849ce3 doc: profiler 2024-04-03 17:53:36 +02:00
Scott Morrison
f3121b0427 fix: omega works as a simp discharger (#3828)
Possibly the more principled fix is to not have `simp` invoke
dischargers under `withReducible`.

In the meantime, this ensures that `falseOrByContra` still succeeds with
`intro1` on a `Not` goal, which previously was breaking `omega` as a
simp discharger.

Closes #3805.
2024-04-03 03:00:00 +00:00
Marc Huisinga
ecf0459122 fix: don't use info nodes before cursor for completion (#3778)
This fixes an issue where the completion would use info nodes before the
cursor for computing completions.

Fixes https://github.com/leanprover/lean4/issues/3462.

ToDo:
- [x] Fix test failures for completions that previously worked by
accident (cc: @Kha)
- [x] stage0 update

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-04-02 08:49:24 +00:00
Joe Hendrix
eacb1790b3 feat: weight lazy discriminator tree results early matches (#3818)
The matches returned by the lazy discriminator tree are partially
constrained by a priority, but ties are broken by the order in which
keys are traversed and the order of declarations.

This PR changes the match key traversal to use an explicit stack rather
than recursion and implicitly changes the order in which results are
returned to favor left-matches first e.g., given the term `f a b` with
constants `f a b`, and a tree with patterns `f a x -> 1` `f x b -> 2`
that have the same priority, this will return `#[1, 2]` since the early
matches for the key `a` are returned before the match for `x` which has
a star.

This appears to address the [lower quality results mentioned on
zulip](https://leanprover.zulipchat.com/#narrow/stream/428973-nightly-testing/topic/Mathlib.20status.20updates/near/429955747).
2024-04-02 07:19:30 +00:00
Leonardo de Moura
c0027d3987 fix: simp only should break Char literals (#3824)
closes #3686
2024-04-02 03:11:40 +00:00
Leonardo de Moura
82ae779218 fix: missing test at addDocString (#3823)
closes #3497
2024-04-02 02:29:14 +00:00
Leonardo de Moura
2dab6939e4 fix: missing withTacticInfoContext (#3822)
closes #3720
2024-04-02 02:15:38 +00:00
Leonardo de Moura
f35fc18c88 fix: simp usedSimps (#3821)
When `discharge?` failed, the `usedSimps` was being restored, but the
cache wasn't. This bug was exposed by issue #3710.

This PR makes the following changes:
- We restore the `cache` at `discharge?`. We use `SMap` to ensure the
operation is efficient.
- We don't need the field `dischargeDepth` anymore at `Simp.Result`.
- `UsedSimps` should use `PHashMap` since it is not used linearly.

closes #3710

---------

Co-authored-by: Mario Carneiro <di.gama@gmail.com>
2024-04-02 00:50:06 +00:00
Leonardo de Moura
0684c95d35 fix: do not lift (<- ...) over pure if-then-else (#3820)
Now, only `(<- ...)`s occurring in the condition of a pure if-then-else
are lifted.
That is, `if (<- foo) then ... else ...` is ok, but `if ... then (<-
foo) else ...` is not. See #3713

closes #3713 

This PR also adjusts this repo. Note that some of the `(<- ...)` were
harmless since they were just accessing some
read-only state.
2024-04-01 21:33:59 +00:00
Leonardo de Moura
a440e63435 fix: loose bound variables at ACLt (#3819)
Closes #3705 

This PR also fixes a performance issue at `ACLt` also exposed by example
at #3705
2024-04-01 20:26:20 +00:00
Leonardo de Moura
4a317ae3f8 fix: .yesWithDeltaI behavior (#3816)
It should not increase the transparency level from `reducible` to
`instances`. See new test.
2024-04-01 02:36:35 +00:00
Leonardo de Moura
0ba21269e8 fix: matcher splitter is code (#3815)
It have to keep it as a private definition for now. We currently only
support duplicate theorems in different modules. Splitters are generated
on demand, and are also used to write code.
2024-04-01 02:14:14 +00:00
Marc Huisinga
e1cadcbfca chore: bump language server version (#3813)
This will allow us to add backwards compatibility in vscode-lean4 for
some recent changes more easily.
2024-03-31 12:47:45 +00:00
Leonardo de Moura
d8d64f1fc0 perf: isDefEq performance issue (#3807)
Fixes a performance problem found by @hargoniX while working on LeanSAT.
2024-03-30 02:15:48 +00:00
Mac Malone
fdd9d6f306 feat: lake lean (#3793)
Adds a `lake lean` CLI command that builds the imports of a Lean file
and then elaborates it via `lean` with the workspace's configuration
(i.e., adding the `moreLeanArgs` / `leanOptions` of the root `package`
and Lake's environment).
2024-03-29 22:54:31 +00:00
Kyle Miller
9cb114eb83 feat: add pp.mvars and pp.mvars.withType (#3798)
* Setting `pp.mvars` to false causes metavariables to pretty print as
`?_`.
* Setting `pp.mvars.withType` to true causes metavariables to pretty
print with type ascriptions.

Motivation: when making tests, it is inconvenient using `#guard_msgs`
when there are metavariables, since the unique numbering is subject to
change.

This feature does not use `⋯` omissions since a metavariable is already
in a sense an omitted term. If repeated metavariables do not appear in
an expression, there is a chance that a term pretty printed with
`pp.mvars` set to false can still elaborate to the correct term, unlike
for other omissions.

(In the future we could consider an option that pretty prints uniquely
numbered metavariables as `?m✝`, `?m✝¹`, `?m✝²`, etc. to be able to tell
them apart, at least in the same pretty printed expression. It would
take care to make sure that these names are stable across different
hovers.)

Closes #3781
2024-03-29 18:03:05 +00:00
Joachim Breitner
b181fd83ef feat: in conv tactic, use try with_reducibe rfl (#3763)
The `conv` tactic tries to close “trivial” goals after itself. As of
now, it uses
`try rfl`, which means it can close goals that are only trivial after
reducing with
default transparency. This is suboptimal

* this can require a fair amount of unfolding, and possibly slow down
the proof
   a lot. And the user cannot even prevent it.
* it does not match what `rw` does, and a user might expect the two to
behave the
   same.

So this PR changes it to `with_reducible rfl`, matching `rw`’s behavior.

I considered `with_reducible eq_refl` to only solve trivial goals that
involve equality,
but not other relations (e.g. `Perm xs xs`), but a discussion on mathlib
pointed out
that it’s expected and desirable to solve more general reflexive goals:


https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Closing.20after.20.60rw.60.2C.20.60conv.60.3A.20.60eq_refl.60.20instead.20of.20.60rfl.60/near/429851605
2024-03-29 11:59:45 +00:00
Joachim Breitner
97e3257ffd chore: un-qualify .induct lemmas in tests (#3804)
now that #3803 is fixed.
2024-03-29 11:34:09 +00:00
Kyle Miller
44ad3e2e34 feat: hovering over binders shows their types (#3797)
Modifies `withBindingBodyUnusedName` to annotate the syntax for the
variable with its corresponding fvar. Now, for example, you can hover
over the variables in `fun x y => ...` in the infoview to see their
types. This change affects notations such as `∃ n, n = 1`, where
hovering over `n` shows that `n : Nat`.

Also adds such annotations for the variables in `let` and `let_fun`.

Implementation note: the variables are annotated with fresh positions
using `nextExtraPos`.

Removes the unused and unnecessary
`Lean.PrettyPrinter.Delaborator.liftMetaM`.

Closes #1618, closes #2737
2024-03-29 03:52:00 +00:00
Mac Malone
ca1cbaa6e9 feat: lake test (#3779)
Adds a `lake test` CLI command that runs a `script` or `lean_exe` tagged
`@[test_runner]` in the workspace's root package.
2024-03-29 03:19:46 +00:00
Leonardo de Moura
7a93a7b877 fix: reserved name resolution (#3803)
This PR includes the following fixes:

- Reserved name resolution inside namespaces
- Equation theorems for `match`er declarations are not private anymore
- Equation theorems for `match`er declarations are realizable
- `foo.match_<idx>.splitter` is now a reserved name
2024-03-29 02:56:48 +00:00
Mac Malone
e54a0d7b89 fix: lake: check normalized packages directory path before rename (#3795)
Normalize the relative packages directory paths in the pre-rename check
to avoid renames if the difference in paths is only in the path
separators. Also adds a log message on rename.
2024-03-29 01:15:59 +00:00
Kyle Miller
b15b971416 fix: require idents come in a column after the start of a command (#3799)
Commands that can optionally parse an `ident` or parse any number of
`ident`s generally should require that the `ident` use `colGt`. This
keeps typos in commands from being interpreted as identifiers.

For example, without this rule,
```
universe u
Open Lean
````
parses the same as `universe u Open Lean`. It would be better to get an
error on `Open`.

This PR adds `checkColGt` to `section`, `namespace`, `end`, `variable`,
and `universe`.

Closes #2684
2024-03-29 01:14:20 +00:00
Leonardo de Moura
9bdb37a9b0 chore: update stage0
Reason: new builtin environment extension
2024-03-28 17:58:33 -07:00
Leonardo de Moura
dee074dcde fix: simp regression introduced by equation theorems for non-recursive definitions 2024-03-28 17:58:33 -07:00
Leonardo de Moura
fe783cb778 feat: save whether a function has been defined by structural or well-founded recursion 2024-03-28 17:58:33 -07:00
Leonardo de Moura
d1c0149e17 chore: fix simproc doc-string (#3800) 2024-03-28 17:54:52 +00:00
James Sully
8af34df2d2 doc: typo in rcases docs (#3796)
"alteration pattern" -> "alternation pattern"
2024-03-28 07:31:01 +00:00
Mac Malone
55b7b07c54 feat: lake: alternative TOML config (#3298)
Adds an alternative TOML configuration format to Lake. 

* Uses TOML v1.0.0 and is fully specification compliant (tested via
[toml-test v1.4.0](https://github.com/toml-lang/toml-test/tree/v1.4.0)).
* Supports package configuration options, Lean libraries, Lean
executables, and dependencies.
* TOML configurations can be generated for new projects via `lake
new|init <pkg> <template>.toml`.
* Supported configurations can be converted to/from TOML via `lake
translate-config <lang>`.
2024-03-28 02:35:02 +00:00
Joe Hendrix
0963f3476c chore: extend GetElem with getElem! and getElem? (#3694)
This makes changes to the `GetElem` class so that it does not lead to
unnecessary overhead in container like `RBMap`.

The changes are to:
1. Make `getElem?` and `getElem!` part of the `GetElem` class so they
can be overridden in instances.
2. Introduce a `LawfulGetElem` class that contains correctness theorems
for `getElem?` and `getElem!` using the original definitions.
3. Reorganize definitions (e.g, by moving `GetElem` out of
`Init.Prelude`) so that the `GetElem` changes are feasible.
4. Provide `LawfulGetElem` instances to complement all existing
`GetElem` instances in Lean core.

To reduce the size of the PR, this doesn't do the work of providing new
`GetElem` instances for `RBMap`, `HashMap` etc. That will be done in a
separate PR (#3688) that depends on this.

---------

Co-authored-by: Mac Malone <tydeu@hatpress.net>
2024-03-28 01:42:00 +00:00
Joe Hendrix
7989f62f70 fix: remove unused try catch (#3794)
This fixes some placeholder code inadvertently contributed.
2024-03-28 01:39:51 +00:00
Kyle Miller
4bacd70b3f feat: add option tactic.customEliminators to be able to turn off custom eliminators for induction and cases (#3655)
This was suggested by Scott Morrison to be able to help projects adjust
to `Nat` having built-in custom eliminators.
2024-03-28 01:14:17 +00:00
Mario Carneiro
775dabd4ce fix: toUInt64LE! and toUInt64BE! are swapped (#3660)
fixes #3657

These functions are mostly not used by lean itself, but it does affect
two occurrences of `ByteArray.toUInt64LE! <$> IO.getRandomBytes 8` which
I left as is instead of switching them to use `toUInt64BE!` to preserve
behavior; but they are random bytes anyway seeded by the OS so it's
unlikely any use of them depending on particular values was sound to
begin with.

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-03-28 01:13:42 +00:00
Kyle Miller
5167324cb8 doc: edit Lean.MVarId.withReverted (#3743)
When it was upstreamed, it lost the mention of "revert/intro pattern",
which is helpful for finding this function. Also extended the
description of the function and clarified some points.

---------

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-03-28 01:12:23 +00:00
Kyle Miller
520cd3f0d6 fix: make generalized field notation for abbreviation types handle optional parameters (#3746)
Closes #3745
2024-03-28 00:59:09 +00:00
Scott Morrison
5b7ec4434e chore: fix rebase suggestion for Mathlib CI (#3701)
Previously we were suggesting rebasing onto the most recently nightly in
the branches history, but that is incorrect and we should *always*
suggest rebasing on `origin/nightly-with-mathlib`.

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2024-03-27 23:46:06 +00:00
Kyle Miller
70924be89c feat: hovering over omission term shows reason for omission (#3751)
This avoids printing the entire docstring for `⋯` when hovering over it,
which is rather long, and instead it gives a brief reason for omission
and what option to set to pretty print the omitted term.
2024-03-27 15:10:20 +00:00
Scott Morrison
02c5700c63 feat: change apply_rfl tactic so that it does not operate on = (#3784)
Previously:

If the `rfl` macro was going to fail, it would:
1. expand to `eq_refl`, which is implemented by
`Lean.Elab.Tactic.evalRefl`, and call `Lean.MVarId.refl` which would:
* either try kernel defeq (if in `.default` or `.all` transparency mode)
  * otherwise try `IsDefEq`
  * then fail.
2. Next expand to the `apply_rfl` tactic, which is implemented by
`Lean.Elab.Tactic.Rfl.evalApplyRfl`, and call `Lean.MVarId.applyRefl`
which would look for lemmas labelled `@[refl]`, and unfortunately in
Mathlib find `Eq.refl`, so try applying that (resulting in another
`IsDefEq`)
3. Because of an accidental duplication, if `Lean.Elab.Tactic.Rfl` was
imported, it would *again* expand to `apply_rfl`.

Now:
1. Same behaviour in `eq_refl`.
2. The `@[refl]` attribute will reject `Eq.refl`, and `MVarId.applyRefl`
will fail when applied to equality goals.
3. The duplication has been removed.
2024-03-27 12:04:22 +00:00
Sebastian Ullrich
3ee1cdf3de chore: CI: continue on test-summary failure 2024-03-27 14:03:10 +01:00
Scott Morrison
94d6286e5a chore: reorganising to reduce imports (#3790)
[Before](https://github.com/leanprover/lean4/files/14772220/oi.pdf) and
[after](https://github.com/leanprover/lean4/files/14772226/oi2.pdf).

This gets `ByteArray`, `String.Extra`, `ToString.Macro` and `RCases` out
of the imports of `omega`. I'd hoped to get `Array.Subarray` too, but
it's tangled up in the list literal syntax. Further progress could come
from make `split` use available `Decidable` instances, so we could pull
out `Classical` (and possibly some of `PropLemmas`).
2024-03-27 11:15:01 +00:00
Sebastian Ullrich
16fdca1cbd chore: test results as job summary (#3715)
Tired of scrolling through and parsing the test output myself
2024-03-27 10:14:33 +00:00
Joachim Breitner
c857d08be6 fix: remove derive_functional_induction (#3788)
this follows up on #3776 and the subsequent stage0 update, now relying
on the reserved name for the induction principles.
2024-03-27 10:08:13 +00:00
Scott Morrison
1a5d064d08 chore: upstream tail-recursive implementations of List operations, and @[csimp] lemmas (#3785) 2024-03-27 08:36:48 +00:00
Henrik Böving
2405fd605e feat: trace non-easy whnf invocations (#3774) 2024-03-27 08:35:22 +00:00
Lean stage0 autoupdater
63290babde chore: update stage0 2024-03-27 07:34:13 +00:00
Scott Morrison
b4caee80a3 chore: rw? uses MVarId.refl not MVarId.applyRfl (#3783)
I think this was in error in my original Mathlib implementation. We're
not interested in relations other than `=`, so there is no point uses
`MVarId.applyRfl`, which just looks up `@[refl]` tagged lemmas and tries
those.

In a separate PR, I will change `MVarId.applyRfl` so it has a flag to
control whether on `=` it should just hand-off to `MVarId.refl`, or
fail. Failure is appropriate in the version we call from the `rfl`
macro, to avoid doing a double `IsDefEq` check on every `rfl`!
2024-03-27 03:02:30 +00:00
Joe Hendrix
b17c47d852 fix: lemma selection improvements to to rw? and lazy discriminator tree (#3769)
This makes several changes to rw? and lazy discrimination trees based on
test failures in rewrite search.

Changes include:
1. Reverting to Mathlib function for candidate lemma priority in rw?
2. Introducing additional filters for auto-generated named in lazy
discriminator tree.
3. Refactoring lazy discriminator values to clarify what is stored.
4. Including star keys in calculation of match closeness in
prioritization.
5. Using more fields in current core context when initializing lazy
discriminator tree and avoiding max heartbeat issues.

---------

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-03-26 23:57:08 +00:00
Joachim Breitner
ab318dda2d feat: use reserved name infrastructure for functional induction (#3776)
no need to enter `derive_functional_induction` anymore.

(Will remove the support for `derive_functional_induction` after the
next stage0 update, since we are already using it in Init.)
2024-03-26 22:25:10 +00:00
Joachim Breitner
301dd7ba16 feat: failing macros to show error from first registered rule (#3771)
fixes #3770

Also start `rfl` with a `fail` message that is hopefully more helpful
than what we get now (see updated test output). This would be a cheaper
way to address #3302 without changing the implementation of rfl (as
tried in #3714).
2024-03-26 22:24:45 +00:00
Joachim Breitner
466ef74ccc feat: functional induction for structural recursion (#3738)
This extends `derive_functional_induction` to work with structural
recursion as well.

It produces the less general, more concrete induction rule where the
induction hypothesis is
specialized for every argument of the recursive call, not just the the
one that the function
is recursing on.

Care is taken so that the induction principle and it's motive take the
arguments in the same
order as the original function.

While I was it, also makes sure that the order of the cases in the
induction principle matches
the order of recursive calls in the function better.

---------

Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-03-26 13:36:24 +00:00
Eric Wieser
e8a2786d6d fix: actually catch the error code from MoveFileEx (#3753)
A user on Zulip [reported seeing an error code of "no
error"](https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/.60lake.20update.60.20broken.20on.20Windows.20.28.3F.29/near/429134334)
here.
2024-03-26 09:00:25 +00:00
Julien Michel
4c0106d757 refactor: simplify Array.findIdx? code (#3648)
This shortens `Array.findIdx?` code, by using termination_by (and
well-founded recursion) instead of a structural recursion trick, with
the intent to make it more proof friendly.

One motivation is that it makes it easier to write a proof that
`Array.findIdx?` and `List.findIdx?` are equivalent. Furthermore, this
will be useful to prove that more complex functions are equivalent.

Closes #3646
2024-03-26 05:11:59 +00:00
Austin Letson
83369f3d9f fix: update System.FilePath.parent to handle edge cases for absolute paths (#3645)
System.FilePath.parent did not return the correct parent path in the
case of absolute file paths

Example of previous behavior
```
(FilePath.mk "/foo").parent -> some (FilePath.mk "")

(System.FilePath.mk "/").parent -> some (FilePath.mk "")
```

The new behavior is based on rust's std::path::Path::parent function (as
previously described in comment in System.FilePath)

Example of updated behavior
```
(System.FilePath.mk "/foo").parent -> some (FilePath.mk "/")

(System.FilePath.mk "/").parent -> none
```

Behavior for relative file paths is unchanged

Closes #3618
2024-03-26 05:09:44 +00:00
Leonardo de Moura
22b5c957e9 chore: rename automatically generated "unfold" theorems (#3767)
Given a definition `foo`, they were previously called `foo._unfold`
until 4.7.0. We tried to rename them to `foo.def`, but it created too
many issues in the Mathlib repo. We decided to rename it again to
`foo.eq_def`. The new name is also consistent with the `eq_<idx>`
theorems generated for different "cases". That is, `foo.eq_def` is the
equality theorem for the whole definition, and `foo.eq_<idx>` is the
equality theorem for case `<idx>`.

cc @semorrison
2024-03-25 21:41:26 +00:00
Leonardo de Moura
a0dac9f546 feat: ignore explicit proofs in canonicalizer (#3766) 2024-03-25 20:52:42 +00:00
Eric Wieser
d8047ddeb1 fix: change Quotient.sound to a theorem (#3765)
The result is a proof, so presumably this should not be a `def`.
2024-03-25 19:28:31 +00:00
Joachim Breitner
e0c6c5d226 fix: functional induction: preseve order of cases better (#3762)
by passing an explicit array of metavariable around, instead of relying
on `getMVarsNoDelayed`, which may return them in unexpected order.
2024-03-25 11:59:29 +00:00
Jon Eugster
3dd811f9ad chore: remove FileMap.lines and add FileMap.getLine (#3237)
`FileMap.lines` is an array that seems to be manually managed to have
the form `#[1, 2, ..., n-1, n-1]` with same length as
`FileMap.positions`. Remove this structure field in favour of
calculating the line number as `min(x+1, positions.size-1)` when needed.

Follow-up on #3221
2024-03-25 10:33:04 +00:00
Scott Morrison
1d245bcb82 chore: revert ToJson/FromJson Sum (#3759) (#3760)
Sorry, this was ill-considered, it doesn't round trip faithfully.
2024-03-25 09:09:44 +00:00
Scott Morrison
a943a79bd3 chore: ToJson/FromJson Sum (#3759) 2024-03-25 07:43:40 +00:00
Joachim Breitner
80d2455b64 fix: prune universe params in functional induction (#3754)
fixes #3752
2024-03-24 10:15:50 +00:00
Kyle Miller
655ec964f5 feat: flatten parent projections when pretty printing structure instance notation (#3749)
Given
```lean
structure A where
  x : Nat

structure B extends A where
  y : Nat
```
rather than pretty printing `{ x := 1, y := 2 : B }` as `{ toA := { x :=
1 }, y := 2 }`, it now pretty prints as `{ x := 1, y := 2 }`.

The option `pp.structureInstances.flatten` controls whether to flatten
structure instances like this.
2024-03-23 09:20:52 +00:00
Kyle Miller
925a6befd4 fix: do not pretty print theorems with generalized field notation (#3750)
For example, pretty print as `Nat.add_comm m n` rather than as
`m.add_comm n`.
2024-03-23 09:20:48 +00:00
Hongyu Ouyang
2ed777b2b4 doc: fix typo in docstring of left (#3748) 2024-03-23 07:39:36 +00:00
Joe Hendrix
6c8976abbe feat: upstream rw? tactic (#3719)
This updates the rw? tactic from Mathlib to use lazy discriminator trees
and upstreams it.

---------

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-03-23 05:01:35 +00:00
Kyle Miller
d39b0415f0 feat: enable pp.fieldNotation.generalized globally (#3744)
Sets the default value to `pp.fieldNotation.generalized` to `true`.
Updates tests, and fixes some minor flaws in the implementation of the
generalized field notation pretty printer.

Now generalized field notation won't be used for any function that has a
`motive` argument. This is intended to prevent recursors from pretty
printing using it as (1) recursors are more like control flow structures
than actual functions and (2) generalized field notation tends to cause
elaboration problems for recursors.

Note: be sure functions that have an `@[app_unexpander]` use
`@[pp_nodot]` if applicable. For example, `List.toArray` needs
`@[pp_nodot]` to ensure the unexpander prints it using `#[...]`
notation.
2024-03-23 02:38:09 +00:00
Kyle Miller
8ce98e62ac fix: typos in release notes (#3742) 2024-03-22 18:25:44 +00:00
Lean stage0 autoupdater
027b2bc38d chore: update stage0 2024-03-22 18:09:36 +00:00
Marc Huisinga
3f8f2b09af chore: more generic import out of date diagnostic (#3739)
The concrete dependency that is stale isn't really actionable
information for users (ideally we'd like something like "amount of
dependencies that will be rebuilt when you restart file"). This also
makes the diagnostic an "information" diagnostic so that non-infoview
users can still see it.

Since we are moving away from using notifications for stale dependency
information, we don't need to provide an ID anymore, either.
2024-03-22 13:13:20 +00:00
Kyle Miller
1f4dea8582 feat: add pp.fieldNotation.generalized for generalized field notation, add @[pp_nodot] attribute (#3737)
Refactors app delaborator, merging in the projection delaborator, to
support pretty printing with generalized field notation.

Renames option `pp.structureProjections` to `pp.fieldNotation` and adds
sub-option `pp.fieldNotation.generalized` to enable/disable generalized
field notation. Adds `@[pp_nodot]` attribute to permanently disable
using field notation for a given declaration.

For now, the default value of `pp.fieldNotation.generalized` is false
since we need a stage0 update to add `@[pp_nodot]` to some core
definitions (such as `List.toArray`) before updating the tests.

[Zulip
discussion](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/.60pp.2EgeneralizedFieldNotation.60/near/425856054)
2024-03-22 08:55:02 +00:00
Scott Morrison
d5a1dce0ae chore: omega notices that 0 ≤ (x : Int) % (y : Int) (#3736) 2024-03-22 02:49:24 +00:00
Kyle Miller
acb188f11c feat: apply pp_using_anonymous_constructor attribute (#3735)
This attribute, which was implemented in #3640, is applied to the
following structures: `Sigma`, `PSigma`, `PProd`, `And`, `Subtype`, and
`Fin`. These were given this attribute in Lean 3.
2024-03-22 00:30:36 +00:00
Lean stage0 autoupdater
d884a946c8 chore: update stage0 2024-03-22 01:16:40 +00:00
Kyle Miller
980e73c368 feat: make in Infoview hovers show docstring (#3663)
The docstring for `⋯` gives information about why the omission term
might appear in an expression, and it helps with discoverability to give
documentation right in the hover.

This was mentioned by Patrick Massot [on
Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Deep.20terms.20ellipses/near/426133597)
as being an issue.
2024-03-22 00:00:23 +00:00
Scott Morrison
67c7729f96 doc: fix HDiv and HMod doc-strings (#3734)
As reported by @loefflerd on
[zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/wrong.20docstring.20for.20integer.20division.3F/near/428076692).
2024-03-21 23:46:41 +00:00
David Thrane Christiansen
966fa800f8 chore: remove the coercion from String to Name (#3589)
This coercion caused difficult-to-diagnose bugs sometimes. Because there
are some situations where converting a string to a name should be done
by parsing the string, and others where it should not, an explicit
choice seems better here.

---------

Co-authored-by: Mac Malone <tydeu@hatpress.net>
2024-03-21 23:46:03 +00:00
Lean stage0 autoupdater
d5701fc912 chore: update stage0 2024-03-22 00:00:55 +00:00
Kyle Miller
ff7a0db099 feat: add pp_using_anonymous_constructor attribute (#3640)
Implements a Lean 3 pretty printer feature. Structures with the
`@[pp_using_anonymous_constructor]` attribute pretty using anonymous
constructor notation (`⟨x, y, z⟩`) rather than structure instance
notation (`{a := x, b := y, c := z}`).

[Zulip
discussion](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/.60pp_using_anonymous_constructor.60/near/425705445)
2024-03-21 23:01:10 +00:00
Sebastian Ullrich
085d01942d fix: restore default of stderrAsMessages (#3733)
Puts trace.compiler back in the info view. Apparently an unintended
change in #3014.
2024-03-21 17:43:29 +00:00
Marc Huisinga
31767aa835 fix: use sticky diags in getInteractiveDiagnostics (#3730)
I forgot to use the sticky diagnostics in `getInteractiveDiagnostics` in
#3247, leading to them not consistently showing up in the "Messages"
panel of the InfoView.
2024-03-21 14:34:22 +00:00
Marc Huisinga
902668dc38 fix: use correct positions for header errors (#3728)
This lead to incorrect diagnostic spans in the editor and resulted in
header errors that did not show up under "Messages" everywhere in the
file because the `fullRange?` property was missing.

Also changes the "Import out of date" warning diagnostic severity to
"Hint" so that it doesn't show up in the "Problems" view.
2024-03-21 14:19:45 +00:00
Joachim Breitner
2867b93d51 chore: replace shell.nix with a devShell in flake.nix (#3717)
as a side effect this pins the “old nixpkgs” revision used by CI for
release builds.
(Not that that old branch is likely to change a lot…)
2024-03-21 13:24:01 +00:00
Mario Carneiro
49f66dc485 perf: rewrite UnusedVariables lint (#3186)
This is a rewrite of the `UnusedVariables` lint to inline and simplify
many of the dependent functions to try to improve the performance of
this lint, which quite often shows up in perf reports.

* The mvar assignment scanning is one of the most expensive parts of the
process, so we do two things to improve this:
  * Lazily perform the scan only if we need it
* Use an object-pointer hashmap to ensure that we don't have quadratic
behavior when there are many mvar assignments with slight differences.
* The dependency on `Lean.Server` is removed, meaning we don't need to
do the LSP conversion stuff anymore. The main logic of reference finding
is inlined.
* We take `fvarAliases` into account, and union together fvars which are
aliases of a base fvar. (It would be great if we had `UnionFind` here.)

More docs will be added once we confirm an actual perf improvement.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-03-21 12:28:57 +00:00
Scott Morrison
164689f00f feat: more BitVec lemmas (#3729) 2024-03-21 11:56:24 +00:00
Arthur Adjedj
bf8b66c6a5 fix: ignore unused alternatives in Ord derive handler (#3725)
Closes #3706

This derive handler's implementation is very similar to `BEq`'s, which
already ignores unused alternative so as to work correctly on indexed
inductive types. This PR simply implements the same solution as the one
present in
[`BEq.lean`](2c15cdda04/src/Lean/Elab/Deriving/BEq.lean (L94)).

After some tests, it doesn't seem like any other derive handler present
in Core suffers from the same issue (though some handlers don't work on
indexed inductives for other reasons).
2024-03-21 10:29:22 +00:00
Sebastian Ullrich
4d4e467392 feat: MonadAlwaysExcept for MonadCacheT (#3726) 2024-03-21 09:01:13 +00:00
Scott Morrison
2c15cdda04 feat: BitVec.ofBoolListLE and theorems (#3721)
Requested by Jeremy Avigad on
[zulip](https://leanprover.zulipchat.com/#narrow/stream/217875-Is-there-code-for-X.3F/topic/explicit.20bitvectors/near/427841343).

---------

Co-authored-by: Mario Carneiro <di.gama@gmail.com>
2024-03-21 04:48:29 +00:00
Lean stage0 autoupdater
4391bc2977 chore: update stage0 2024-03-20 22:45:34 +00:00
Marc Huisinga
40b5282ec2 fix: use correct module name in references (#3722)
#3656 used the wrong name in `RefIdent`, which lead to "Find References"
being broken. I really need to set up some tests for this functionality
...
2024-03-20 20:28:01 +00:00
Sebastian Ullrich
afbf8759e1 fix: deadlock in IO.Promise.resolve (#3693) 2024-03-20 12:47:52 +00:00
Leni Aniva
3ab1c23500 fix: Build failure of nix build . on macOS (#3712)
Closes bug #3711 

Now we have
```
$ nix build .#stage0
$ ls result/lib/lean/
libInit_shared.dylib* libleanshared.dylib*
```
2024-03-18 21:39:39 +00:00
Scott Morrison
846300038f fix: make attribute based rfl tactic builtin (#3708) 2024-03-18 11:39:59 +00:00
Lean stage0 autoupdater
01432ffc5a chore: update stage0 2024-03-18 12:20:03 +00:00
Marc Huisinga
3c82f9ae12 feat: diagnostics for stale dependencies (#3247)
Sends a diagnostic informing the user to run Restart File when a file
dependency is saved.

Based on #3014 because this feature was easier to implement with the new
architecture.

ToDo:
- [x] Adjust vscode-lean4 to display a notification when this diagnostic
appears in a non-annoying way
(https://github.com/leanprover/vscode-lean4/pull/393)
- [x] Use a file watcher to identify changes to files not tracked by VS
Code
- [x] Rebase onto master when #3014 is merged
2024-03-18 10:38:38 +00:00
Kitamado
7abc1fdaac doc: fix docstring of List.span (#3707)
see
https://leanprover.zulipchat.com/#narrow/stream/113488-general/topic/docstring.20of.20.60List.2Espan.60.20is.20wrong
2024-03-18 10:26:47 +00:00
Liu Yuxi
2d18eff544 doc: lake: fix typo (#3704)
Closes #3703
2024-03-17 18:23:21 +00:00
Scott Morrison
66541b00a6 feat: upstream Std's rfl tactic (#3671)
This allows tagging lemmas with `@[refl]`, that will then by used by
`rfl`.

This is preparatory to upstreaming Mathlib's `convert` tactic.
2024-03-17 07:06:13 +00:00
Scott Morrison
f1f9b57df9 feat: upstream apply helper tactics from Mathlib (#3670)
These are used in Mathlib's `congr!` and `convert` tactics, which will
be upstreamed soon.

---------

Co-authored-by: Kyle Miller <kmill31415@gmail.com>
2024-03-17 06:47:56 +00:00
Scott Morrison
88b1751b54 chore: fix namespaces in recently upstreamed tactics (#3672) 2024-03-17 06:41:40 +00:00
Timo Carlin-Burns
8e96d7ba1d refactor: clean up public API around Array.eraseIdx (#3676)
- Removes the public definitions `Array.eraseIdxAux` and
`Array.eraseIdxSzAux` which were implementation details.
- Motivation: `Array.eraseIdxAux` and `Array.eraseIdxSzAux` were clearly
not intended to remain public, but simply making them private would make
it inconvenient to unfold them when writing proofs in Std.
- Adds documentation comments to the public `Array.eraseIdx`-related
definitions which remain.
- Removes `Array.eraseIdx'` which was just `Array.feraseIdx` wrapped in
a subtype and adds `Array.size_feraseIdx` to prove the subtype property
as a standalone theorem.

Co-Authored-By: Daniel Windham <daniel@atlascomputing.org>
2024-03-17 06:25:10 +00:00
Scott Morrison
9ee10aa3eb chore: in combined CI, check for required Std tag, then Mathlib (#3702) 2024-03-17 01:29:47 +00:00
Scott Morrison
811bedfa76 chore: fix combined CI for mathlib (#3700)
Previously, if there was a `nightly-testing-YYYY-MM-DD` tag at Std, but
not Mathlib, we were erroneously proceeding with Mathlib CI, and hence
using a probably-broken version of Mathlib.
2024-03-16 23:42:45 +00:00
Joachim Breitner
0b01ceb3bb fix: substVars in functional inductions removed valuable information (#3695)
using the `substVars` tactic on the goal can remove too much
information, as it does not take into account that the `motive` may
depend on the fixed parameters.

This is fixed by etracting `substVar` from `subst` which expects the
`x`, not the `h : x = rhs`, and then using this tactic on the local
declarations _after_ the `motive` exclusively.
2024-03-16 14:55:31 +00:00
Joachim Breitner
4c57da4b0f feat: infer termination arguments like xs.size - i (#3666)
a common pattern for recursive functions is
```
def countUp (n i acc : Nat) : Nat :=
  if i < n then
    countUp n (i+1) (acc + i)
  else
    acc
```
where we increase a value `i` until it hits an upper bound. This is
particularly common with array processing functions:
```
$ git grep 'termination_by.*size.*-' src/|wc -l
26
```

GuessLex now recognizes this pattern. The general approach is:

For every recursive call, check if the context contains hypotheses of
the form `e₁ < e₂` (or similar comparisions), and then consider `e₂ -
e₁` as a termination argument.

Currently, this only fires when `e₁` and `e₂` only depend on the
functions parameters, but not local let-bindings or variables bound in
local pattern matches.

Duplicates are removed.

In the table showing the termination argument failures, long termination
arguments are now given a number and abbreviated as e.g. `#4` in the
table headers.

More examples in the test file, here as some highlights:
```
def distinct (xs : Array Nat) : Bool :=
  let rec loop (i j : Nat) : Bool :=
    if _ : i < xs.size then
      if _ : j < i then
        if xs[j] = xs[i] then
          false
        else
          loop i (j+1)
      else
        loop (i+1) 0
    else
      true
  loop 0 0
```
infers
```
termination_by (Array.size xs - i, i - j)
```
and the weird functions where `i` goes up or down
```
def weird (xs : Array Nat) (i : Nat) : Bool :=
  if _ : i < xs.size then
    if _ : 0 < i then
      if xs[i] = 42 then
        weird xs.pop (i - 1)
      else
        weird xs (i+1)
    else
      weird xs (i+1)
  else
    true
decreasing_by all_goals simp_wf; omega
```
infers
```
termination_by (Array.size xs - i, i)
```
but unfortunately needs `decreasing_by` pending the “big
decreasing_tactic refactor” that
I expect we’ll want to do at some point.
2024-03-16 12:27:35 +00:00
Joachim Breitner
f0ff01ae28 refactor: pass Measures around as Expr in GuessLex (#3665)
this refactor prepares GuessLex to be able to infer more complex
termination arguments.

As a side-effect it fixes an (obscure) bug where `sizeOf` would be
applied to a term of the wrong type and thus a wrong `SizeOf` instance
could be inferred.
2024-03-16 10:25:55 +00:00
Joe Hendrix
0ec8862103 chore: migrate find functionality into LazyDiscrTree (#3685)
This migrates some lookup functionality from library_search to a more
generic version in LazyDiscrTree.

It is a step towards `rw?` in core.
2024-03-16 01:01:53 +00:00
Lean stage0 autoupdater
f70895ede5 chore: update stage0 2024-03-15 16:30:21 +00:00
Sebastian Ullrich
557777dd37 chore: CI: mark "Build matrix complete" as cancelled if builds cancelled (#3690) 2024-03-15 12:30:48 +00:00
Marc Huisinga
e47d8ca5cd fix: periodically refresh semantic tokens (#3691)
Based on #3619 that was reverted because of nondeterministic test
failures. This PR should resolve those.
2024-03-15 11:58:50 +00:00
Sebastian Ullrich
3b4b2cc89d fix: do not dllexport symbols in core static libraries (#3601)
On Windows, we now compile all core `.o`s twice, once with and without
`dllexport`, for use in the shipped dynamic and static libraries,
respectively. On other platforms, we export always as before to avoid
the duplicate work.

---------

Co-authored-by: tydeu <tydeu@hatpress.net>
2024-03-15 11:58:34 +00:00
Marc Huisinga
14654d802d chore: revert periodically refresh semantic tokens (#3619) (#3689)
This reverts commit 4e3a8468c3 for PR
#3619. It looks like the CI in that commit didn't inform me that a test
was broken by the PR, so I managed to commit it despite the broken test.
2024-03-15 09:17:53 +00:00
Leonardo de Moura
173b956961 feat: reserved names (#3675)
- Add support for reserved declaration names. We use them for theorems
generated on demand.
- Equation theorems are not private declarations anymore.
- Generate equation theorems on demand when resolving symbols.
- Prevent users from creating declarations using reserved names. Users
can bypass it using meta-programming.

See next test for examples.
2024-03-15 00:33:22 +00:00
Joachim Breitner
022b2e4d96 refactor: termination arguments as Expr, not Syntax (#3658)
Before, the termination argument as inferred by `GuessLex` was passed
further
on as `Syntax`, to be elaborated later in `WF.Rel`.

This didn’t feel quite right anymore. In particular if we want to teach
`GuessLex` about guessing more complex termination arguments like
`xs.size -
i`, using `Expr` here is more natural.

So this introduces `TerminationArgument` based on an `Expr` to be used
here.

A side-effect of how the termination arguments are elaborated is that
the unused
variables linter will now look at `termination_by` variables, and that
parameters
past the colon are not even invisibly in scope, so `‹_›` will not find
them
See https://github.com/leanprover-community/mathlib4/pull/11370/files
for examples
of fixing these changes.
2024-03-14 23:51:53 +00:00
Marc Huisinga
4e3a8468c3 fix: periodically refresh semantic tokens (#3619)
This PR fixes an issue where the file worker would not provide the
client with semantic tokens until the file had been elaborated
completely. The file worker now also tells the client to refresh its
semantic tokens after running "Restart File". This PR is based on #3271.
2024-03-14 17:10:04 +00:00
Marc Huisinga
78a72741c6 fix: jump to correct definition when names overlap (#3656)
Fixes #1170.

This PR adds the module name to `RefIdent` in order to distinguish
conflicting names from different files. This also fixes related issues
in find-references or the call hierarchy feature.
It also adds some docstrings and stylistically refactors a bunch of
code.
2024-03-14 16:21:19 +00:00
Marc Huisinga
795e332fb3 feat: server -> client requests (#3271)
This PR adds support for requests from the server to the client in the
language server. It is based on #3014 and was developed during an
experiment for #3247 that unfortunately did not go anywhere.
2024-03-14 16:00:32 +00:00
Joe Hendrix
1151d73a55 fix: use builtin_initialize in library_search (#3677)
This replaces a few uses of initialize with builtin_initialize, and
removes some unneeded functionality added when it was unclear if lazy
discriminator trees would be efficient enough.
2024-03-14 15:28:00 +00:00
Sebastian Ullrich
fb2ec54b60 chore: build Lean .os in parallel to rest of core (#3682)
Previously, we only did `Init/*.{o,olean}+Lean/*.olean` in parallel
2024-03-14 15:14:37 +00:00
Joachim Breitner
f89ed40618 refactor: ArgsPacker (#3621)
This introduces the `ArgsPacker` module and abstraction, to replace the
exising `PackDomain`/`PackMutual` code. The motivation was that we now
have more uses besides `Fix.lean` (`GuessLex` and `FunInd`), and the
code was spread in various places.

The goals are

* consistent function naming withing the the `PSigma` handling, the
`PSum` handling, and the combined interface
* avoid taking a type apart just based on the `PSigma`/`PSum` nesting,
to be robust in case the user happens to be using `PSigma`/`PSum`
somewhere. Therefore, always pass an `arity` or `numFuncs` or `varNames`
around.
* keep all the `PSigma`/`PSum` encoding logic contained within one
module (`ArgsPacker`), and keep that module independent of its users (so
no `EqnInfos` visible here).
 * pick good variable names when matching on a packed argument
* the unary function now is either called `fun1._unary` or
`fun1._mutual`, never `fun1._unary._mutual`.

This file has less heavy dependencies than `PackMutual` had, so build
parallelism is improved as well.
2024-03-14 14:59:40 +00:00
Sebastian Ullrich
68eaf33e86 feat: snapshot trees and language processors (#3014)
This is the foundation for work on making processing in the language
server both more fine-grained (incremental tactics) as well as parallel.
2024-03-14 13:40:08 +00:00
Sebastian Ullrich
0959bc45d2 chore: CI: temporarily disable fsanitize build 2024-03-14 15:36:28 +01:00
Leonardo de Moura
995726f75f chore: fix tests 2024-03-13 21:15:48 -07:00
Leonardo de Moura
214179b6b9 chore: update stage0 2024-03-13 21:15:48 -07:00
Leonardo de Moura
9ee1ff2435 chore: remove bootstrapping workaround 2024-03-13 21:15:48 -07:00
Leonardo de Moura
653eb5f66e chore: update stage0 2024-03-13 21:15:48 -07:00
Leonardo de Moura
2c8fd7fb95 chore: avoid reserved name
TODO: update state0 and cleanup
2024-03-13 21:15:48 -07:00
Leonardo de Moura
8d2adf521d feat: allow duplicate theorems to be imported 2024-03-13 12:57:41 -07:00
Leonardo de Moura
612d97440b chore: incorrectly annotated theorems 2024-03-13 12:37:58 -07:00
Leonardo de Moura
0f19332618 chore: update stage0 2024-03-13 12:37:58 -07:00
Leonardo de Moura
84b0919a11 feat: type of theorems must be propositions 2024-03-13 12:37:58 -07:00
Hongyu Ouyang
e61d082a95 doc: fix typo in USize.size docstring (#3664) 2024-03-13 10:51:24 +00:00
Leonardo de Moura
600412838c fix: auxiliary definition nested in theorem should be def if its type is not a proposition (#3662) 2024-03-13 09:38:37 +00:00
Joachim Breitner
a81205c290 feat: conv => calc (#3659)
`calc` is great for explicit rewriting, `conv` is great to say where to
rewrite, so it's natural to want `calc` as a `conv` tactic.

Zulip disucssion at
https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/idiom.20for.20using.20calc.20to.20rewrite.20the.20goal/near/424269608

Fixes #3557.
2024-03-13 09:03:39 +00:00
Leonardo de Moura
2003814085 chore: rename automatically generated equational theorems (#3661)
cc @nomeata
2024-03-13 07:56:27 +00:00
Scott Morrison
317adf42e9 chore: add @[simp] to Nat.succ_eq_add_one, and cleanup downstream (#3579) 2024-03-13 05:35:52 +00:00
Leonardo de Moura
5aca09abca fix: add Canonicalizer.lean and use it to canonicalize terms in omega (#3639) 2024-03-12 23:18:56 +00:00
Joachim Breitner
07dac67847 feat: guard_msgs to escapes trailing newlines (#3617)
This makes trailing whitespace visible and protectes them against
trimming by the editor, by appending the symbol ⏎ to such a line (and
also to any line that ends with such a symbol, to avoid ambiguities in
the case the message already had that symbol).

(Only the code action output / docstring parsing is affected; the error
message as sent
to the InfoView is unaffected.)

Fixes #3571
2024-03-12 16:35:14 +00:00
thorimur
5cf4db7fbf fix: make dsimp? use and report simprocs (#3654)
Modifies `dsimpLocation'` (which implements `dsimp?`) to take a
`simprocs : SimprocsArray` argument, like `simpLocation` and
`dsimpLocation`. This ensures that the behavior of `dsimp` matches
`dsimp?`.

---

Closes #3653
2024-03-12 05:17:58 +00:00
Mac Malone
b2ae4bd5c1 feat: allow noncomputable unsafe definitions (#3647)
Enables the combination of `noncomputable unsafe` to be used for
definitions. Outside of pure theory, `noncomputable` is also useful to
prevent Lean from compiling a definition which will be implemented with
external code later. Such definitions may also wish to be marked
`unsafe` if they perform morally impure or memory-unsafe functions.
2024-03-12 02:46:42 +00:00
Joe Hendrix
c43a6b5341 chore: upstream Std.Data.Int (#3635)
This depends on #3634.
2024-03-11 21:40:48 +00:00
Lean stage0 autoupdater
1388f6bc83 chore: update stage0 2024-03-11 17:22:37 +00:00
Joachim Breitner
d9b6794e2f refactor: termination_by parser to use binderIdent (#3652)
this way we should be able to use `elabBinders` to parse the binders.
2024-03-11 16:29:56 +00:00
Mac Malone
ebefee0b7d chore: response file to avoid arg limits in lean static lib build (#3612) 2024-03-11 16:14:24 +00:00
Joachim Breitner
32dcc6eb89 feat: GuessLex: avoid writing sizeOf in termination argument when not needed (#3630)
this makes `termination_by?` even slicker.

The heuristics is agressive in the non-mutual case (will omit `sizeOf`
if the argument is non-dependent and the `WellFoundedRelation` relation
is via `sizeOfWFRel`.

In the mutual case we'd also have to check the arguments, as they line
up in the termination argument, have the same types. I did not bother at
this point; in the mutual case we omit `sizeOf` only if the argument
type is `Nat`.

As a drive-by fix, `termination_by?` now also works on functions that
have only one plausible measure.
2024-03-10 22:57:10 +00:00
Leonardo de Moura
1d3ef577c2 chore: disable some tests on Windows (#3642)
This is a temporary workaround for a limitation on Windows shared
libraries. We are getting errors of the form:
```
ld.lld: error: too many exported symbols (got 65572, max 65535)
```
2024-03-09 23:48:41 +00:00
Kyle Miller
45fccc5906 feat: custom eliminators for induction and cases tactics, and beautiful eliminators for Nat (#3629)
Replaces `@[eliminator]` with two attributes `@[induction_eliminator]`
and `@[cases_eliminator]` for defining custom eliminators for the
`induction` and `cases` tactics, respectively.

Adds `Nat.recAux` and `Nat.casesAuxOn`, which are eliminators that are
defeq to `Nat.rec` and `Nat.casesOn`, but these use `0` and `n + 1`
rather than `Nat.zero` and `Nat.succ n`.

For example, using `induction` to prove that the factorial function is
positive now has the following goal states (thanks also to #3616 for the
goal state after unfolding).
```lean
example : 0 < fact x := by
  induction x with
  | zero => decide
  | succ x ih =>
    /-
    x : Nat
    ih : 0 < fact x
    ⊢ 0 < fact (x + 1)
    -/
    unfold fact
    /-
    ...
    ⊢ 0 < (x + 1) * fact x
    -/
    simpa using ih
```

Thanks to @adamtopaz for initial work on splitting the `@[eliminator]`
attribute.
2024-03-09 15:31:51 +00:00
Kyle Miller
3acd77a154 fix: make elabTermEnsuringType respect errToSorry when there is a type mismatch (#3633)
Floris van Doorn [reported on
Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/have.20tactic.20error.20recovery/near/425283053)
that it is confusing that the `have : T := e` tactic completely fails if
the body `e` is not of type `T`. This is in contrast to `have : T := by
exact e`, which does not completely fail when `e` is not of type `T`.

This ends up being caused by `elabTermEnsuringType` throwing an error
when it fails to insert a coercion. Now, it detects this case, and it
checks the `errToSorry` flag to decide whether to throw the error or to
log the error and insert a `sorry`.

This is justified by `elabTermEnsuringType` being a frontend to
`elabTerm`, which inserts `sorry` on error.

An alternative would be to make `ensureType` respect `errToSorry`, but
there exists code that expects being able to catch when `ensureType`
fails. Making such code manipulate `errToSorry` seems error prone, and
this function is not a main entry point to the term elaborator, unlike
`elabTermEnsuringType`.
2024-03-09 15:30:47 +00:00
Leonardo de Moura
b39042b32c fix: eta-expanded instances at SynthInstance.lean (#3638)
Remark: this commit removes the `jason1.lean` test. Motivation: It
breaks all the time due to changes we make, and it is not clear anymore
what it is testing.

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2024-03-08 20:37:38 +00:00
Joe Hendrix
6dd4f4b423 chore: upstream Std.Data.Nat (#3634)
This migrates lemmas about Nat `compare`, `min`, `max`, `dvd`, `gcd`,
`lcm` and `div`/`mod` from Std to Lean itself.

Std still has some additional recursors, `CoPrime` and a few additional
definitions that might merit further discussion prior to upstreaming.
2024-03-08 17:00:46 +00:00
Mac Malone
123dcb964c feat: lake: LEAN_GITHASH override (#3609)
If the `LEAN_GITHASH` environment variable is set, Lake will now use it
instead of the detected Lean's githash when computing traces for builds
and the elaborated Lake configuration. This override allows one to
replace the Lean version used by a library
(e.g., Mathlib) without completely rebuilding it, which is useful for
testing custom builds of Lean.
2024-03-08 15:03:07 +00:00
Patrick Massot
ccac989dda doc: expand an error message about compacting closures (#3627)
Provide a hint of where the error message may come from.
2024-03-07 20:02:23 +00:00
Kyle Miller
f336525f31 fix: make delabConstWithSignature avoid using inaccessible names (#3625)
The `delabConstWithSignature` delaborator is responsible for pretty
printing constants with a declaration-like signature, with binders, a
colon, and a type. This is used by the `#check` command when it is given
just an identifier.

It used to accumulate binders from pi types indiscriminately, but this
led to unfriendly behavior. For example, `#check String.append` would
give
```
String.append (a✝ : String) (a✝¹ : String) : String
```
with inaccessible names. These appear because `String.append` is defined
using patterns, so it never names these parameters.

Now the delaborator stops accumulating binders once it reaches an
inaccessible name, and for example `#check String.append` now gives
```
String.append : String → String → String
```
We do not synthesize names for the sake of enabling binder syntax
because the binder names are part of the API of a function — one can use
`(arg := ...)` syntax to pass arguments by name. The delaborator also
now stops accumulating binders once it reaches a parameter with a name
already seen before — we then rely on the main delaborator to provide
that parameter with a fresh name when pretty printing the pi type.

As a special case, instance parameters with inaccessible names are
included as binders, pretty printing like `[LT α]`, rather than
relegating them (and all the remaining parameters) to after the colon.
It would be more accurate to pretty print this as `[inst✝ : LT α]`, but
we make the simplifying assumption that such instance parameters are
generally used via typeclass inference. Likely `inst✝` would not
directly appear in pretty printer output, and even if it appears in a
hover, users can likely figure out what is going on. (We may consider
making such `inst✝` variables pretty print as `‹LT α›` or
`infer_instance` in the future, to make this more consistent.)

Something we note here is that we do not do anything to make sure
parameters that can be used as named arguments actually appear named
after the colon (nor do we assure that the names are the correct names).
For example, one sees `foo : String → String → String` rather than `foo
: String → (baz : String) → String`. We can investigate this later if it
is wanted.

We also give `delabConstWithSignature` a `universes` flag to enable
turning off pretty printing universe levels parameters.

Closes #2846
2024-03-07 18:14:06 +00:00
Sebastian Ullrich
3921257ece feat: thread initialization for reverse FFI (#3632)
Makes it possible to properly allocate and free thread-local runtime
resources for threads not started by Lean itself
2024-03-07 17:02:47 +00:00
Sebastian Ullrich
6af7a01af6 fix: stray dbgTraceVal in trace children elision (#3622) 2024-03-07 09:44:25 +00:00
Leonardo de Moura
611b174689 fix: ofScientific at simp (#3628)
closes #2159
2024-03-07 00:11:31 +00:00
Leonardo de Moura
d731854d5a chore: update stage0 2024-03-06 15:29:04 -08:00
Leonardo de Moura
3218b25974 doc: for issue #2835 2024-03-06 15:29:04 -08:00
Leonardo de Moura
ef33882e2f test: issue #2835
closes #2835
2024-03-06 15:29:04 -08:00
Leonardo de Moura
4208c44939 chore: update stage0 2024-03-06 15:29:04 -08:00
Leonardo de Moura
423fed79a9 feat: simplify .arrow ctor at DiscrTree.lean 2024-03-06 15:29:04 -08:00
Leonardo de Moura
5302b7889a fix: fold raw Nat literals at dsimp (#3624)
closes #2916

Remark: this PR also renames `Expr.natLit?` ==> `Expr.rawNatLit?`.
Motivation: consistent naming convention: `Expr.isRawNatLit`.
2024-03-06 18:29:20 +00:00
Joe Hendrix
46cc00d5db chore: add example to explanation cond_decide is not simp (#3615)
This just adds a concrete example to the `cond_decide` lemma to explain
why it is not a simp rule.
2024-03-06 16:58:12 +00:00
Joachim Breitner
0072d13bd4 feat: MatcherApp.transform: Try to preserve alt’s variable name (#3620)
this makes the ugly `fst`/`snd` variable names in the functional
induction principles go away.

Ironically I thought in order to fix these name, I should touch the
mutual/n-ary argument packing code used for well-founded recursion, and
embarked on a big refactor/rewrite of that code, only to find that at
least this particular instance of the issue was somewhere else. Hence
breaking this into its own PR; the refactoring will follow (and will
also improve some other variable names.)
2024-03-06 15:56:17 +00:00
Leonardo de Moura
09bc477016 feat: better support for reducing Nat.rec (#3616)
closes #3022

With this commit, given the declaration
```
def foo : Nat → Nat
  | 0 => 2
  | n + 1 => foo n
```
when we unfold `foo (n+1)`, we now obtain `foo n` instead of `foo
(Nat.add n 0)`.
2024-03-06 13:28:07 +00:00
Sebastian Ullrich
f0a762ea4d chore: CI: temporarily disable test binary check on Windows 2024-03-06 09:00:38 +01:00
Leonardo de Moura
30a61a57c3 chore: disable compiler tests on Windows 2024-03-05 20:24:01 -08:00
Leonardo de Moura
794228a982 refactor: Offset.lean and related files (#3614)
Motivation: avoid the unfold and check idiom.
This commit also minimize dependencies at `Offset.lean`.

closes #2615
2024-03-05 19:40:15 -08:00
Joe Hendrix
6cf82c3763 fix: update LazyDiscrTree to not reuse names when caching (#3610)
This fixes an issue discovered in Mathlib with the meta cache being
poisoned by using a name generator. It is difficult to reproduce due to
the name collisions being rare, but here is a minimal module with
definitions that result in an error:

```lean
prelude
universe u

inductive Unit2 : Type where
  | unit : Unit2

inductive Eq2 {α : Sort u} : α → α → Prop where
  | refl (a : α) : Eq2 a a

structure Subtype2 {α : Sort u} (p : α → Prop) where
  val : α

def End (α) := α → α
theorem end_app_eq (α : Type u) (f : End α) (a : α) : Eq2 (f a) (f a) := Eq2.refl _
theorem Set.coe_eq_subtype {α : Type u} (s : α → Prop) : Eq2 (Subtype2 s) (Subtype2 s) := Eq2.refl _
def succAboveCases {_ : Unit2} {α : Unit2 → Sort u} (i : Unit2) (v : α i) : α i := v
theorem succAbove_cases_eq_insertNth : Eq2 @succAboveCases.{u + 1} @succAboveCases.{u + 1} := Eq2.refl _
```

Removing any of thee last 5 definitions avoids the error. Testing
against Mathlib shows this PR fixes the issue.
2024-03-06 02:32:22 +00:00
Scott Morrison
01f0fedef8 feat: further shaking of Nat/Int/Omega (#3613) 2024-03-05 23:43:36 +00:00
Scott Morrison
b8ff951cd1 feat: restore Bool.and_xor_distrib_(left|right) (#3604)
I think these were dropped in #3508, and Mathlib needs them.
2024-03-05 22:22:21 +00:00
Leonardo de Moura
da869a470b chore: update stage0 2024-03-05 14:42:05 -08:00
Leonardo de Moura
acdb0054d5 feat: use dsimprocs at dsimp 2024-03-05 14:42:05 -08:00
Leonardo de Moura
63b068a77c chore: remove auxiliary functions used for bootstrapping 2024-03-05 14:42:05 -08:00
Leonardo de Moura
a4143ded64 chore: update stage0 2024-03-05 14:42:05 -08:00
Leonardo de Moura
02efb19aad chore: prepare to remove auxiliary functions used for bootstrapping 2024-03-05 14:42:05 -08:00
Leonardo de Moura
74c1ce1386 chore: use builtin_dsimproc when appropriate 2024-03-05 14:42:05 -08:00
Leonardo de Moura
1da65558d0 chore: update stage0 2024-03-05 14:42:05 -08:00
Leonardo de Moura
b24fbf44f3 feat: dsimproc command
Simplification procedures that produce definitionally equal results.

WIP
2024-03-05 14:42:05 -08:00
Marc Huisinga
f986f69a32 fix: getInteractiveDiagnostics off-by-one error (#3608)
This bug is the real cause of leanprover/vscode-lean4#392. 
At the end of a tactic state, the client calls
`getInteractiveDiagnostics` with a range `[last line of proof, last line
of proof + 1)`. The `fullRange` span of the `unresolved goals` error
however is something like `[(first line of proof, start character),
(last line of proof, nonzero end character)).
Since it operates on line numbers, `getInteractiveDiagnostics` would
then check whether `[last line of proof, last line of proof + 1)` and
`[first line of proof, last line of proof)` intersect, which is false
because of the excluded upper bound on the latter interval, despite the
fact that the end character in the last line may be nonzero.

This fix adjusts the intersection logic to use `[first line of proof,
last line of proof]` if the end character is nonzero.

Closes leanprover/vscode-lean4#392.
2024-03-05 17:21:10 +00:00
Leonardo de Moura
436d7befa5 fix: dsimp should reduce kernel projections (#3607)
closes #3395
2024-03-05 14:56:27 +00:00
Leonardo de Moura
414f0eb19b fix: bug at Result.mkEqSymm (#3606)
`cache` and `dischargeDepth` fields were being reset.
2024-03-05 14:37:09 +00:00
Scott Morrison
bf6d9295a4 chore: shaking imports in Init.Data.Nat/Int (#3605) 2024-03-05 13:29:35 +00:00
Marc Huisinga
06f4963069 feat: partial words import completion (#3602)
This PR enables import auto-completion to complete partial words in
imports.

Other inconsistencies that I've found in import completion already seem
to be fixed by #3014. Since it will be merged soon, there is no need to
invest time to fix these issues on master.
2024-03-05 13:20:07 +00:00
Joachim Breitner
8038604d3e feat: functional induction (#3432)
This adds the concept of **functional induction** to lean.

Derived from the definition of a (possibly mutually) recursive function,
a **functional
induction principle** is tailored to proofs about that function. For
example from:

```
def ackermann : Nat → Nat → Nat
  | 0, m => m + 1
  | n+1, 0 => ackermann n 1
  | n+1, m+1 => ackermann n (ackermann (n + 1) m)
derive_functional_induction ackermann
```
we get
```
ackermann.induct (motive : Nat → Nat → Prop) (case1 : ∀ (m : Nat), motive 0 m)
  (case2 : ∀ (n : Nat), motive n 1 → motive (Nat.succ n) 0)
  (case3 : ∀ (n m : Nat), motive (n + 1) m → motive n (ackermann (n + 1) m) → motive (Nat.succ n) (Nat.succ m))
  (x x : Nat) : motive x x
```

At the moment, the user has to ask for the functional induction
principle explicitly using
```
derive_functional_induction ackermann
```

The module docstring of `Lean/Meta/Tactic/FunInd.lean` contains more
details on the
design and implementation of this command.

More convenience around this (e.g. a `functional induction` tactic) will
follow eventually.


This PR includes a bunch of `PSum`/`PSigma` related functions in the
`Lean.Tactic.FunInd`
namespace. I plan to move these to `PackArgs`/`PackMutual` afterwards,
and do some cleaning
up as I do that.

---------

Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-03-05 13:02:05 +00:00
Scott Morrison
ce77518ef5 feat: restore Bool.and_xor_distrib_(left|right) 2024-03-05 23:49:47 +11:00
Joachim Breitner
fbd9c076c0 chore: run nix-ci whenever we run ci (#3600)
this unifies the `on` settings between nix-ci and ci, less confusion
when adding a label doesn’t trigger all the CI stuff.
2024-03-05 09:11:19 +00:00
Scott Morrison
ae492265fe chore: cleanup a bitblast proof (#3598) 2024-03-05 04:59:58 +00:00
Scott Morrison
c4a784d6a3 feat: more BitVec lemmas (#3597) 2024-03-05 04:47:53 +00:00
Scott Morrison
def564183c feat: checklist for release process (#3536)
This is still WIP: the checklist for release candidates will get
finished as I do the release of `v4.7.0-rc1`.

---------

Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-03-05 02:55:17 +00:00
Alex Keizer
46bf4b69b6 feat: add lemmas about BitVec.concat and bitwise ops (#3487)
Show how the various bitwise ops (`and`, `or`, `not`, and `xor`)
distribute over `concat`.
2024-03-05 02:48:10 +00:00
Scott Morrison
89ec60befe feat: lemmas about BitVec (#3593)
Basic API lemmas for BitVec, motivated by thinking about bitblasting.
2024-03-05 02:41:47 +00:00
Scott Morrison
f48079eb90 chore: begin development cycle for v4.8.0 (#3596) 2024-03-05 02:15:37 +00:00
Joe Hendrix
01104cc81e chore: bool and prop lemmas for Mathlib compatibility and improved confluence (#3508)
This adds a number of lemmas for simplification of `Bool` and `Prop`
terms. It pulls lemmas from Mathlib and adds additional lemmas where
confluence or consistency suggested they are needed.

It has been tested against Mathlib using some automated test
infrastructure.

That testing module is not yet included in this PR, but will be included
as part of this.

Note. There are currently some comments saying the origin of the simp
rule. These will be removed prior to merging, but are added to clarify
where the rule came from during review.

---------

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-03-04 23:56:30 +00:00
Leonardo de Moura
37450d47e2 fix: bug at elimOptParam (#3595)
`let_expr` uses `cleanupAnnotations` which consumes `optParam` type
annotations.

cc @nomeata
2024-03-04 23:56:00 +00:00
Scott Morrison
e814fc859e chore: cherry-picking v4.6.1 release notes (#3592) 2024-03-04 12:59:00 +00:00
Marc Huisinga
093e1cf22a test: add language server startup benchmark (#3558)
Benchmark to catch future regressions as the one fixed in #3552.
2024-03-04 09:01:51 +00:00
Leonardo de Moura
e6d6855a85 chore: missing double backticks (#3587) 2024-03-04 03:02:35 +00:00
Leonardo de Moura
bba4ef3728 feat: simprocs for folding numeric literals (#3586)
This PR folds exposed `BitVec` (`Fin`, `UInt??`, and `Int`) ground
literals.
cc @shigoel
2024-03-04 02:51:04 +00:00
Scott Morrison
3ad078fec9 chore: updates to RELEASES.md (#3585) 2024-03-04 02:32:30 +00:00
Leonardo de Moura
8689a56a5d feat: #print equations <decl-name> command (#3584) 2024-03-04 02:32:20 +00:00
Scott Morrison
870c6d0dc4 chore: replacing proofs in Init/Data/Nat/Bitwise/Lemmas with omega (#3576)
Replaces some tedious proofs with `omega`, and take advantage of `omega`
powerups to remove some preparatory steps.
2024-03-04 02:19:31 +00:00
Scott Morrison
ad901498fa chore: add release notes for #3507 and #3509 (#3583) 2024-03-04 00:55:53 +00:00
Kyle Miller
acb1b09fbf fix: expression tree elaborator for relations now localizes error messages to the LHS or RHS (#3442)
Added `withRef` when processing the LHS or RHS. Without this, in an
expression such as `true = ()` the entire expression would be
highlighted with "type mismatch, `()` has type `Unit` but is expected to
have type `Bool`". Now the error is localized to `()`.

This behavior was pointed out [on
Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/error.20location.20bug/near/422665805).
2024-03-04 00:53:32 +00:00
Scott Morrison
791142a7ff feat: Nat.mul_mod (#3582)
Proves
`Nat.mod_mul : x % (a * b) = x % a + a * (x / a % b)` and
`Nat.mod_pow_succ : x % b ^ (k + 1) = x % b ^ k + b ^ k * ((x / b ^ k) %
b)`, helpful for bitblasting.
2024-03-03 23:31:07 +00:00
Scott Morrison
015af6d108 chore: use match_expr in omega (#3577) 2024-03-03 22:22:28 +00:00
Kyle Miller
04385b7fb9 doc: small improvements to docstrings for let and have tactics (#3560) 2024-03-03 22:00:32 +00:00
Joachim Breitner
2510808ebf chore: add unicode directory name to gitignore (#3565)
fixes #3358

---------

Co-authored-by: Mac Malone <tydeu@hatpress.net>
2024-03-03 20:19:17 +00:00
Leonardo de Moura
9f305fb31f fix: rename_i in macro (#3581)
closes #3553

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-03-03 19:05:37 +00:00
Sebastian Ullrich
380dd9e6e7 fix: free threadpool threads before process exit 2024-03-03 20:12:46 +01:00
Sebastian Ullrich
908b98dad8 fix: task_manager termination under Emscripten 2024-03-03 20:12:46 +01:00
Leonardo de Moura
a4d41beab1 perf: match_expr join points (#3580)
We use `let_delayed` to elaborate `match_expr` join points, which
elaborate the body of the `let` before its value. Thus, there is a
difference between:
- `let_delayed f (x : Expr) := <val>; <body>`
- `let_delayed f := fun (x : Expr) => <val>; <body>`

In the latter, when `<body>` is elaborated, the elaborator does not know
that `f` takes an argument of type `Expr`, and that `f` is a function.
Before this commit ensures the former representation is used.
2024-03-03 18:15:49 +00:00
Leonardo de Moura
95f28be088 fix: generalize excessive resource usage (#3575)
closes #3524
2024-03-03 17:58:11 +00:00
Leonardo de Moura
c66c5bb45b fix: simp? suggests generated equations lemma names (#3573)
closes #3547

---------

Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2024-03-02 23:59:35 +00:00
Leonardo de Moura
870de4322c fix: missing atomic at match_expr parser (#3572) 2024-03-02 21:55:07 +00:00
Joachim Breitner
4fdc243179 refactor: simplify some nomatch with nofun (#3564)
and also don’t wrap `nomatch` with `False.elim`; it is not necessary, as
`nomatch` already inhabits any type.
2024-03-02 20:43:31 +00:00
Leonardo de Moura
8a3c9cafb9 chore: update stage0 2024-03-02 10:07:15 -08:00
Leonardo de Moura
826f0580a6 fix: propagate expected type at do-match_expr 2024-03-02 10:07:15 -08:00
Leonardo de Moura
0359ff753b chore: use __do_jp workaround, and "implementation detail" variables at match_expr macro 2024-03-02 10:07:15 -08:00
Leonardo de Moura
8b2710c8b3 chore: use let_expr to cleanup code 2024-03-02 10:07:15 -08:00
Leonardo de Moura
0199228784 chore: update stage0 2024-03-02 08:16:18 -08:00
Leonardo de Moura
17e498c11f feat: expand let_expr macros 2024-03-02 08:16:18 -08:00
Leonardo de Moura
54ff38aa5f chore: update stage0 2024-03-02 08:16:18 -08:00
Leonardo de Moura
ecfaf8f3e7 feat: add let_expr notation 2024-03-02 08:16:18 -08:00
Leonardo de Moura
3c0e575fe0 feat: add matchExprPat parser 2024-03-02 08:16:18 -08:00
Leonardo de Moura
49f41a6224 chore: update stage0 2024-03-01 22:33:14 -08:00
Leonardo de Moura
7a27b04d50 feat: monadic match_expr 2024-03-01 22:33:14 -08:00
Leonardo de Moura
f777e0cc85 feat: macro expander for match_expr terms 2024-03-01 22:33:14 -08:00
Leonardo de Moura
64adb0627a feat: add auxiliary functions for compiling match_expr 2024-03-01 22:33:14 -08:00
Leonardo de Moura
ea9a417371 chore: update stage0 2024-03-01 22:33:14 -08:00
Leonardo de Moura
70d9106644 feat: match_expr parsers 2024-03-01 22:33:14 -08:00
Marc Huisinga
9cf3fc50c7 doc: update RELEASES.md for #3552 (#3561) 2024-03-02 00:27:21 +00:00
Joe Hendrix
78726c936f chore: add library_search and #check_tactic to 4.7 RELEASES.md (#3549)
Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-03-02 00:13:08 +00:00
Marc Huisinga
7e944c1a30 fix: load references asynchronously (#3552)
In v4.6.0, there was a significant regression in initial server startup
performance because the .ilean files got bigger in #3082 and we load the
information stored in all .ilean files synchronously when the server
starts up.

This PR makes this loading asynchronous. The trade-off is that requests
that are issued right after the initial server start when the references
are not fully loaded yet may yield incomplete results.

Benchmark for this in a separate PR soon after this one.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-03-01 13:57:52 +00:00
Scott Morrison
18306db396 chore: protect Int.add_right_inj et al (#3551)
Reducing some name conflicts in Mathlib.
2024-03-01 13:01:39 +00:00
Scott Morrison
570b50dddd chore: correct statement of Int.pow_zero, and protected theorems (#3550) 2024-03-01 12:38:02 +00:00
David Thrane Christiansen
43d6eb144e chore: add error recovery to RELEASES.md (#3540)
Adds the missing RELEASES.md from #3413. Apologies for the oversight!
2024-03-01 05:38:18 +00:00
Siddharth
ed02262941 feat: generalize msb_eq_decide to also handle the zero width case (#3480)
Note that this is a strict generalization of the previous statemens of
`getLsb_last` and `msb_eq_decide` that worked for bitwidths `>= 1`.
2024-02-29 22:46:32 +00:00
Joe Hendrix
c0dfe2e439 feat: BitVec int lemmas (#3474)
This introduces lemma support for BitVec.ofInt/BitVec.toInt as well as
lemmas upstreamed from Std and Mathlib for reasoning about emod and
bmod.
2024-02-29 20:48:57 +00:00
Sebastian Ullrich
61fba365f2 fix: revert shared library split on non-Windows platforms (#3529)
Avoids the performance hit and fixes #3528.
2024-02-29 19:15:01 +00:00
Marcus Rossel
0362fcea69 chore: remove redundant 'generalizing' (#3544) 2024-02-29 13:24:14 +00:00
Marcus Rossel
60d056ffdf doc: fix typos (#3543)
The doc comment on
[Lean.Meta.viewSubexpr](https://leanprover-community.github.io/mathlib4_docs/Lean/Meta/ExprLens.html#Lean.Meta.viewSubexpr)
also seems broken, but I don't know how to fix it.
2024-02-29 13:23:19 +00:00
Marcus Rossel
dc0f026e64 chore: remove redundant '..' pattern in match of 'Level.zero' (#3545) 2024-02-29 13:22:04 +00:00
Kyle Miller
67c9498892 doc: update RELEASES.md for #3495 (#3518) 2024-02-29 11:34:00 +00:00
Joachim Breitner
dc0f771561 doc: fix markdown indentation in RELEASES.md (#3542)
and while at it, unify how to style links (include “RFC”, “issue” in the
link)
2024-02-29 10:52:26 +00:00
Marc Huisinga
970b6e59b1 doc: update RELEASES.md for #3460 and #3482 (#3527) 2024-02-29 10:42:54 +00:00
Joe Hendrix
b9f9ce874d chore: have library search drop star only symbols (#3534)
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-02-29 07:09:02 +00:00
Scott Morrison
5a33091732 chore: restore %$tk 2024-02-29 17:34:15 +11:00
Scott Morrison
b762567174 chore: update stage0 2024-02-29 17:34:15 +11:00
Scott Morrison
819a32a9eb chore: upstream show_term
add missing prelude
2024-02-29 17:34:15 +11:00
Scott Morrison
755de48ff3 chore: upstream orphaned tests from Std (#3539) 2024-02-29 04:12:52 +00:00
Leonardo de Moura
37cd4cc996 fix: match-expression when patterns cover all cases of a BitVec finite type (#3538) 2024-02-29 02:24:47 +00:00
Leonardo de Moura
e53ae5d89e chore: remove leftovers (#3537) 2024-02-29 02:12:08 +00:00
Joe Hendrix
69e33efa2f chore: One sided BitVec.toNat equality lemmas (#3533) 2024-02-29 00:25:40 +00:00
Scott Morrison
973cbb186b chore: begin moving orphaned tests from Std (#3535) 2024-02-29 00:09:51 +00:00
Joe Hendrix
9afca1c3a9 feat: port check_tactic commands from Std and add test cases (#3532)
This also adds several Array lemmas from std after cleaning up proofs
2024-02-28 23:32:54 +00:00
Leonardo de Moura
e1acdcd339 fix: get_elem_tactic_trivial regression (#3531) 2024-02-28 23:14:15 +00:00
Scott Morrison
dc4c2b14d3 chore: begin moving orphaned tests from Std 2024-02-29 10:54:19 +11:00
Joe Hendrix
2312c15ac6 chore: port librarySearch tests from std (#3530)
Needed List.partitionMap for test to complete, so ported it too.
2024-02-28 17:24:17 +00:00
Joachim Breitner
fa058ed228 fix: include let bindings when determining altParamNums for eliminators (#3505)
Else the `case` will now allow introducing all necessary variables.

Induction principles with `let` in the types of the cases will be more
common with #3432.

This implementation no longer reduces the type as it goes, but really
only counts
manifest foralls and lets. I find this more sensible and predictable: If
you have
```
theorem induction₂_symm {P : EReal → EReal → Prop} (symm : Symmetric P) …
```
then previously, writing
```
case symm => 
```
would actually bring a fresh `x` and `y` and variable `h : P x y` into
scope and produce a
goal of `P y x`, because `Symmetric P` happens to be
```
def Symmetric := ∀ ⦃x y⦄, x ≺ y → y ≺ x
```

After this change, after `case symm =>` will leave `Symmetric P` as the
goal.

This gives more control to the author of the induction hypothesis about
the actual
goal of the cases. This shows up in mathlib in two places; fixes in
https://github.com/leanprover-community/mathlib4/pull/11023.
I consider these improvements.
2024-02-28 13:14:34 +00:00
Lean stage0 autoupdater
17b8880983 chore: update stage0 2024-02-28 11:50:07 +00:00
Joachim Breitner
b9c4a7e51d feat: termination_by? (#3514)
the user can now write `termination_by?` to see the termination argument
inferred by GuessLex, and turn it into `termination_by …` using the “Try
this” widget or a code action.

To be done later, maybe: Avoid writing `sizeOf` if it's not necessary.
2024-02-28 10:53:17 +00:00
Kyle Miller
08e149de15 fix: make omission syntax be a builtin syntax (part 2)
Re-enables `⋯` processing that was disabled during the move to a builtin.
Adds tests.
2024-02-28 09:23:17 +01:00
Kyle Miller
37fd128f9f chore: update stage0 2024-02-28 09:23:17 +01:00
Kyle Miller
a3226d4fe4 fix: make omission syntax be a builtin syntax
When editing core Lean, the `pp.proofs` feature causes goal states to fail to display in the Infoview, instead showing only "error when printing message: unknown constant '«term⋯»'". This PR moves the `⋯` syntax from Init.NotationExtra to Lean.Elab.BuiltinTerm

It also makes it so that `⋯` elaborates as `_` while logging a warning, rather than throwing an error, which should be somewhat more friendly when copy/pasting from the Infoview.

Closes #3476
2024-02-28 09:23:17 +01:00
Leonardo de Moura
a23292f049 feat: add option tactic.skipAssignedInstances := true for backward compatibilty (#3526)
When using `set_option tactic.skipAssignedInstances false`, `simp` and
`rw` will synthesize instance implicit arguments even if they have
assigned by unification. If the synthesized argument does not match the
assigned one the rewrite is not performed. This option has been added
for backward compatibility.
2024-02-28 05:52:29 +00:00
Siddharth
d683643755 feat: add intMax (#3492) 2024-02-28 05:43:22 +00:00
Scott Morrison
7cce64ee70 feat: omega doesn't check for defeq atoms (#3525)
```
example (a : Nat) :
    (((a + (2 ^ 64 - 1)) % 2 ^ 64 + 1) * 8 - 1 - (a + (2 ^ 64 - 1)) % 2 ^ 64 * 8 + 1) = 8 := by
  omega
```
used to time out, and now is fast.

(We will probably make separate changes later so the defeq checks would
be fast in any case here.)
2024-02-28 05:41:29 +00:00
Leonardo de Moura
86ca8e32c6 feat: improve simp discharge trace messages (#3523) 2024-02-28 04:39:57 +00:00
Mac Malone
a179469061 fix: lake: detection of custom Lake build dir (#3506)
During the switch to `.lake`, I overlooked updating the paths in
`LakeInstall`. This fixes that and helps prevent further mistakes by
using the same default definitions as the package configuration itself.
2024-02-28 00:34:51 +00:00
Leonardo de Moura
aed29525ab fix: simp trace issues (#3522) 2024-02-27 23:19:25 +00:00
Kyle Miller
6e24a08907 feat: improve error messages and docstring for decide tactic (#3422)
The `decide` tactic produces error messages that users find to be
obscure. Now:
1. If the `Decidable` instance reduces to `isFalse`, it reports that
`decide` failed because the proposition is false.
2. If the `Decidable` instance fails to reduce, it explains what
proposition it failed for, and it shows the reduced `Decidable` instance
rather than the `Decidable.decide` expression. That expression tends to
be less useful since it shows the unreduced `Decidable` argument (plus
it's a lot longer!)

Examples:
```lean
example : 1 ≠ 1 := by decide
/-
tactic 'decide' proved that the proposition
  1 ≠ 1
is false
-/

opaque unknownProp : Prop

open scoped Classical in
example : unknownProp := by decide
/-
tactic 'decide' failed for proposition
  unknownProp
since its 'Decidable' instance reduced to
  Classical.choice ⋯
rather than to the 'isTrue' constructor.
-/
```

When reporting the error, `decide` only shows the whnf of the
`Decidable` instance. In the future we could consider having it reduce
all decidable instances present in the term, which can help with
determining the cause of failure (this was explored in
8cede580690faa5ce18683f168838b08b372bacb).
2024-02-27 23:07:38 +00:00
Kyle Miller
321ef5b956 fix: make Lean.Internal.liftCoeM and Lean.Internal.coeM unfold (#3404)
The elaboration function `Lean.Meta.coerceMonadLift?` inserts these
coercion helper functions into a term and tries to unfolded them with
`expandCoe`, but because that function only unfolds up to
reducible-and-instance transparency, these functions were not being
unfolded. The fix here is to give them the `@[reducible]` attribute.
2024-02-27 22:17:46 +00:00
Joachim Breitner
9c00a59339 feat: use omega in default decreasing_trivial (#3503)
with this, more functions will be proven terminating automatically,
namely those where after `simp_wf`, lexicographic order handling,
possibly `subst_vars` the remaining goal can be solved by `omega`.

Note that `simp_wf` already does simplification of the goal, so
this adds `omega`, not `(try simp) <;> omega` here.

There are certainly cases where `(try simp) <;> omega` will solve more 
goals (e.g. due to the `subst_vars` in `decreasing_with`), and
`(try simp at *) <;> omega` even more. This PR errs on the side of
taking
smaller steps.

Just appending `<;> omega` to the existing
`simp (config := { arith := true, failIfUnchanged := false })` call
doesn’t work nicely, as that leaves forms like `Nat.sub` in the goal
that
`omega` does not seem to recognize.

This does *not* remove any of the existing ad-hoc `decreasing_trivial`
rules based on `apply` and `assumption`, to not regress over the status
quo (these rules may apply in cases where `omega` wouldn't “see”
everything, but `apply` due to defeq works).

Additionally, just extending makes bootstrapping easier; early in `Init`
where
`omega` does not work yet these other tactics can still be used.

(Using a single `omega`-based tactic was tried in #3478 but isn’t quite
possible yet, and will be postponed until we have better automation
including forward reasoning.)
2024-02-27 18:53:36 +00:00
Joachim Breitner
d7ee5ba1cb feat: use omega in the get_elem tactic (#3515)
with this, hopefully more obvious array accesses will be handled
automatically.

Just like #3503, this PR does not investiate which of the exitsting
tactics in `get_elem_tactic_trivial` are subsumed now and could be
dropped without (too much) breakage.
2024-02-27 18:52:04 +00:00
Sebastian Ullrich
850bfe521c doc: split interface/implementation docs on ite (#3517)
The second part is an implementation notice, as evidenced by the
reference to "users".
2024-02-27 18:50:31 +00:00
Leonardo de Moura
855fbed024 fix: regression on match expressions with builtin literals (#3521) 2024-02-27 18:49:44 +00:00
Scott Morrison
2e4557dbd0 chore: default for librarySearch tactic argument (#3495)
There's a downstream tactic in Mathlib that calls `librarySearch`, and
it's easier it is has a default provided.
2024-02-27 14:53:25 +00:00
Lean stage0 autoupdater
7d5b6cf097 chore: update stage0 2024-02-27 10:00:46 +00:00
Kyle Miller
6e408ee402 feat: apply app unexpanders for all prefixes of an application (#3375)
Before, app unexpanders would only be applied to entire applications.
However, some notations produce functions, and these functions can be
given additional arguments. The solution so far has been to write app
unexpanders so that they can take an arbitrary number of additional
arguments. However, as reported in [this Zulip
thread](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/pretty.20printer.20bug/near/420662236),
this leads to misleading hover information in the Infoview. For example,
while `HAdd.hAdd f g 1` pretty prints as `(f + g) 1`, hovering over `f +
g` shows `f`. There is no way to fix the situation from within an app
unexpander; the expression position for `HAdd.hAdd f g` is absent, and
app unexpanders cannot register TermInfo.

This commit changes the app delaborator to try running app unexpanders
on every prefix of an application, from longest to shortest prefix. For
efficiency, it is careful to only try this when app delaborators do in
fact exist for the head constant, and it also ensures arguments are only
delaborated once. Then, in `(f + g) 1`, the `f + g` gets TermInfo
registered for that subexpression, making it properly hoverable.

The app delaborator is also refactored, and there are some bug fixes:
- app unexpanders only run when `pp.explicit` is false
- trailing parameters in under-applied applications are now only
considered up to reducible & instance transparency, which lets, for
example, optional arguments for `IO`-valued functions to be omitted.
(`IO` is a reader monad, so it's hiding a pi type)
- app unexpanders will no longer run for delaborators that use
`withOverApp`
- auto parameters now always pretty print, since we are not verifying
that the provided argument equals the result of evaluating the tactic

Furthermore, the `notation` command has been modified to generate an app
unexpander that relies on the app delaborator's new behavior.

The change to app unexpanders is reverse-compatible, but it's
recommended to update `@[app_unexpander]`s in downstream projects so
that they no longer handle overapplication themselves.
2024-02-27 07:04:17 +00:00
Leonardo de Moura
c5fd88f5e1 feat: set literal unexpander (#3513) 2024-02-27 03:02:41 +00:00
Leonardo de Moura
d6df1ec32f fix: register builtin rpc methods (#3512) 2024-02-27 00:15:21 +00:00
Leonardo de Moura
5e101cf983 feat: use attribute command to add and erase simprocs (#3511) 2024-02-26 23:41:49 +00:00
Leonardo de Moura
bb0695b017 fix: simp? should track unfolded let-decls (#3510)
closes #3501
2024-02-26 20:49:24 +00:00
Leonardo de Moura
4a14ea3a5c fix: rewrite tactic should not try to synthesize instances that have been inferred by unification (#3509) 2024-02-26 20:18:07 +00:00
Leonardo de Moura
f0b4902f7a fix: simp should not try to synthesize instance implicit arguments that have been inferred by unification (#3507) 2024-02-26 20:17:55 +00:00
Mac Malone
e73495e5a6 fix: lake: warn on fetch cloud release failure (#3401)
If Lake fails to download a cloud release, it will now print a warning
indicating that it is falling back to a local build. For example:

```
[0/2] Downloading cloud_test cloud release
[0/2] Building CloudTest
error: > curl -s -f -o [...] -L [...]
error: external command `curl` exited with code 22
warning: fetching cloud release failed; falling back to local build
```
2024-02-26 13:55:19 +00:00
Leonardo de Moura
17fb8664f8 fix: issue when matching Int literals (#3504) 2024-02-26 13:09:07 +00:00
Sebastian Ullrich
992000a672 fix: C++ exceptions across shared libraries on Linux (#3500)
Server interruptions in C++ started to fail after #3421
2024-02-26 10:35:11 +00:00
Marc Huisinga
eb48e6908b feat: sorted call hierarchy items & no private prefix (#3482)
Sorts call hierarchy items and strips the private prefix to make the
call hierarchy more readable.
2024-02-26 09:43:47 +00:00
Marc Huisinga
a929c0176d fix: auto-completion bugs and performance (#3460)
This PR addresses several performance issues in the auto-completion
implementation. It also fixes a number of smaller bugs related to
auto-completion.

In a file with `import Mathlib`, the performance of various kinds of
completions has improved as follows:
- Completing `C`: 49000ms -> 1400ms
- Completing `Cat`: 14300ms -> 1000ms
- Completing `x.` for `x : Nat`: 3700ms -> 220ms
- Completing `.` for an expected type of `Nat`: 11000ms -> 180ms

The following bugs have been fixed as well:
- VS Code never used our custom completion order. Now, the server fuzzy
completion score decides the order that completions appear in.
- Dot auto-completion for private types did not work at all. It does
now.
- Completing `.<identifier>` (where the expected type is used to infer
the namespace) did not filter by the expected type and instead displayed
all matching constants in the respective namespace. Now, it uses the
expected type for filtering. Note that this is not perfect because
sub-namespaces are technically correct completions as well (e.g.
`.Foo.foobar`). Implementing this is future work.
- Completing `.` was often not possible at all. Now, as long as the `.`
is not used in a bracket (where it may be used for the anonymous lambda
feature, e.g. `(. + 1)`), it triggers the correct completion.
-  Fixes #3228.
- The auto-completion in `#check` commands would always try to complete
identifiers using the full declaration name (including namespaces) if it
could be resolved. Now it simply uses the identifier itself in case
users want to complete this identifier to another identifier.

## Details

Regarding completion performance, I have more ideas on how to improve it
further in the future.

Other changes:
- The feature that completions with a matching expected type are sorted
to the top of the server-side ordering was removed. This was never
enabled in VS Code because it would use its own completion item order
and when testing it I found it to be more confusing than useful.
- In the server-side ordering, we would always display keywords at the
top of the list. They are now displayed according to their fuzzy match
score as well.

The following approaches have been used to improve performance:
- Pretty-printing the type for every single completion made up a
significant amount of the time needed to compute the completions. We now
do not pretty-print the type for every single completion that is offered
to the user anymore. Instead, the language server now supports
`completionItem/resolve` requests to compute the type lazily when the
user selects a completion item.
- Note that we need to keep the amount of properties that we compute in
a resolve request to a minimum. When the server receives the resolve
request, the document state may have changed from the state it was in
when the initial auto-completion request was received. LSP doesn't tell
us when it will stop sending resolve requests, so we cannot keep this
state around, as we would have to keep it around forever.
LSP's solution for this dilemma is to have servers send all the state
they need to compute a response to a resolve request to the client as
part of the initial auto completion response (which then sends it back
as part of the resolve request), but this is clearly infeasible for all
real language servers where the amount of state needed to resolve a
request is massive.
This means that the only practical solution is to use the current state
to compute a response to the resolve request, which may yield an
incorrect result. This scenario can especially occur when using
LiveShare where the document is edited by another person while cycling
through available completions.
- Request handlers can now specify a "header caching handler" that is
called after elaborating the header of a file. Request handlers can use
this caching handler to compute caches for information stored in the
header. The auto-completion uses this to pre-compute non-blacklisted
imported declarations, which in turn allow us to iterate only over
non-blacklisted imported declarations where we would before iterate over
all declarations in the environment. This is significant because
blacklisted declarations make up about 4/5 of all declarations.
- Dot completion now looks up names modulo private prefixes to figure
out whether a declaration is in the namespace of the type to the left of
the dot instead of first stripping the private prefix from the name and
then comparing it. This has the benefit that we do not need to scan the
full name in most cases.

This PR also adds a couple of regression tests for fixed bugs, but *no
benchmarks*. We will add these in the future when we add proper support
for benchmarking server interaction sessions to our benchmarking
architecture.

All tests that were broken by producing different completion output
(empty `detail` field, added `sortText?` and `data?` fields) have been
manually checked by me to be still correct before replacing their
expected output.
2024-02-26 09:43:19 +00:00
Leonardo de Moura
88fbe2e531 chore: missing prelude 2024-02-25 11:44:42 -08:00
Leonardo de Moura
b9b7f97d42 chore: update stage0 2024-02-25 11:44:42 -08:00
Leonardo de Moura
c96f815137 fix: command_code_action initialization 2024-02-25 11:44:42 -08:00
Leonardo de Moura
bc8511ccbf chore: builtin_command_code_action for #guard_msgs 2024-02-25 11:44:42 -08:00
Leonardo de Moura
bfb981d465 chore: update stage0 2024-02-25 11:44:42 -08:00
Leonardo de Moura
48a9a99a97 feat: add builtin_command_code_action attribute 2024-02-25 11:44:42 -08:00
Leonardo de Moura
365243e9a3 chore: code_action_provider => builtin_code_action_provider 2024-02-25 11:44:42 -08:00
Leonardo de Moura
ade3256625 chore: remove workaround 2024-02-25 11:44:42 -08:00
Leonardo de Moura
02e4fe0b1c chore: update stage0 2024-02-25 11:44:42 -08:00
Leonardo de Moura
5514b8f1fd chore: move command_code_action attribute syntax to Init 2024-02-25 11:44:42 -08:00
Leonardo de Moura
2edde7b376 chore: initialize => builtin_initialize 2024-02-25 11:44:42 -08:00
Scott Morrison
3dd10654e1 chore: upstream Std.CodeAction.*
Remove tactic_code_action

rearrange

oops

.

add tests

import file

Update src/Lean/Elab/Tactic/GuardMsgs.lean

Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>

Update src/Lean/Elab/Tactic/GuardMsgs.lean

Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>

fix namespace

move GuardMsgs

cleanup
2024-02-25 11:44:42 -08:00
Leonardo de Moura
72d233d181 fix: match patterns containing int values and constructors (#3496) 2024-02-25 17:44:08 +00:00
Leonardo de Moura
9e5e0e23b2 perf: mkSplitterProof 2024-02-24 16:08:07 -08:00
Leonardo de Moura
33bc46d1a7 fix: complete Fin match 2024-02-24 16:08:07 -08:00
Leonardo de Moura
056cb75ee0 fix: match literal pattern support
The equation lemmas were not using the standard representation for literals.
2024-02-24 16:08:07 -08:00
Leonardo de Moura
66be8b9d4c fix: ToExpr instance for Fin 2024-02-24 16:08:07 -08:00
Leonardo de Moura
6d569aa7b5 refactor: use LitValue.lean to implement simprocs 2024-02-24 16:08:07 -08:00
Leonardo de Moura
335fef4396 feat: add helper functions for recognizing builtin literals 2024-02-24 16:08:07 -08:00
Sebastian Ullrich
a3596d953d fix: clean build after update-stage0 (#3491) 2024-02-24 15:54:50 +00:00
Leonardo de Moura
5b15e1a9f3 fix: disable USize simprocs (#3488) 2024-02-24 02:37:39 +00:00
Leonardo de Moura
d179d6c8d7 perf: bitvector literals in match patterns (#3485) 2024-02-24 00:38:46 +00:00
Leonardo de Moura
3ead33bd13 chore: isNatLit => isRawNatLit 2024-02-23 15:18:30 -08:00
Leonardo de Moura
51fe66b9eb test: toExpr tests 2024-02-23 15:16:12 -08:00
Leonardo de Moura
c48d020255 feat: add ToExpr instances for UInt?? types 2024-02-23 15:16:12 -08:00
Leonardo de Moura
f7e74320df feat: add ToExpr instance for BitVec 2024-02-23 15:16:12 -08:00
Leonardo de Moura
72f90bff9d feat: add ToExpr instance for Fin 2024-02-23 15:16:12 -08:00
Leonardo de Moura
2defc58159 chore: rename isNatLit => isRawNatLit
Motivation: consistency with `mkRawNatLit`
2024-02-23 15:16:12 -08:00
Leonardo de Moura
338aa5aa7c fix: Std.BitVec occurrences at OmegaM.lean 2024-02-23 15:15:57 -08:00
Leonardo de Moura
4d4b79757d chore: move BitVec to top level namespace
Motivation: `Nat`, `Int`, `Fin`, `UInt??` are already in the top level
namespace. We will eventually define `UInt??` and `Int??` using `BitVec`.
2024-02-23 15:15:57 -08:00
Joe Hendrix
710c3ae9e8 chore: upstream exact? and apply? from Std (#3447)
This is still a draft PR, but includes the core exact? and apply?
tactics.

Still need to convert to builtin syntax and test on Std.

---------

Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-02-23 21:55:24 +00:00
Joachim Breitner
87e7c666e2 refactor: drop sizeOf_get_lt, duplicate of sizeOf_get (#3481) 2024-02-23 18:43:28 +00:00
Sebastian Ullrich
60f30a46cf chore: CI: typo 2024-02-23 18:23:00 +01:00
Joachim Breitner
6c828ee9eb doc: fix references to Std.Tactic.Omega in comments (#3479) 2024-02-23 16:05:32 +00:00
Sebastian Ullrich
4d94147643 chore: build Lean in parallel to Init (#3455)
A, for now, less problematic subset of #3103
2024-02-23 10:44:58 +00:00
Wojciech Nawrocki
9dfb93bbe9 fix: unnecessary map (#3470)
This came up while looking into cancelling RPC requests. It turns out
that `IO.cancel (Task.map t f)` does *not* cancel `t` (see
[here](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Should.20cancelling.20a.20purely.20mapped.20task.20cancel.20the.20original.3F)),
so it is important to avoid mapping here. It also turns out that the
`map` is completely unnecessary: it lifts from `Except` to `Except`. So
while from the cancellation perspective this is perhaps more of a
bandaid than a solution, it at least doesn't hurt.
2024-02-23 09:27:57 +00:00
Sebastian Ullrich
8bf9d398af chore: CI: flag Lean modules not using prelude (#3463)
Co-authored-by: Henrik Böving <hargonix@gmail.com>
2024-02-23 08:06:55 +00:00
Scott Morrison
5a32473f66 feat: replace ToExpr Int (#3472)
The current `ToExpr Int` instance produces `@Int.ofNat (@OfNat.ofNat Nat
i ...)` for nonnegative `i` and `@Int.negSucc (@OfNat.ofNat Nat (-i+1)
...)` for negative `i`.

However it should be producing `@OfNat.ofNat Int i ...` for nonnegative
`i`, and `@Neg.neg ... (@OfNat.ofNat Int (-i) ...)` for negative `i`.
2024-02-23 02:30:05 +00:00
Alex Keizer
b9b4d8f41d feat: add BitVec.toNat_concat (#3471)
Make `x.toNat * 2 + b.toNat` the simp normal form of `(concat x
b).toNat`.

The choice for multiplication and addition was inspired by `Nat.bit_val`
from Mathlib.
Also, because we have considerably more lemmas about multiplication and
`_ + 1` than about shifts and `_ ||| 1`.
2024-02-23 02:16:01 +00:00
Scott Morrison
4e87d7f173 chore: rename Bool.toNat_le_one (#3469)
To merge after #3457.

---------

Co-authored-by: Alex Keizer <alex@keizer.dev>
2024-02-23 02:07:18 +00:00
Siddharth
e17e0d36a7 feat: omega uses b^(e+1) = b^e*b when b constant (#3450)
This is very helpful when dealing with bitvectors, where a case analysis
on the bitwidth leaves one with hypotheses of the form `x<2^(Nat.succ
w)`.

Design decisions I am unsure about:
- Is creating a helper `succ?` the correct way to match on the exponent
`e+1`?
- I'm not certain why the prior call to `Int.ofNat_pow` also checked
that the exponent was a ground natural. I removed this, since we now
explicitly handle cases where the exponent is a term of the form `e+1`.

---------

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
Co-authored-by: Joe Hendrix <joe@lean-fro.org>
Co-authored-by: Alex Keizer <alex@keizer.dev>
2024-02-23 01:17:03 +00:00
Alex Keizer
8bf6475e10 feat: add BitVec.getLsb_concat (#3457)
First (baby)-step to a `concat`-based `bitblast`: a characterization of
`concat` in terms of `getLsb`.

The proof might benefit slightly from a `toNat_concat` lemma, but I
wasn't sure what the normal form there should be, so I avoided it.

---------

Co-authored-by: Scott Morrison <scott@tqft.net>
2024-02-23 00:58:27 +00:00
Scott Morrison
7f7d9bdaaf chore: cleanup in BitVec/Bitblast.lean (#3468) 2024-02-23 00:47:30 +00:00
Scott Morrison
0824442a6f chore: remove @[simp] from some new BitVec lemmas (#3466) 2024-02-23 00:26:06 +00:00
Alex Keizer
815200eaad refactor: make BitVec.carry take bitvector arguments (#3461)
Every usage of `carry` followed the pattern: `carry _ x.toNat y.toNat`,
so we've refactorod `carry` to take the `BitVec`s as arguments, and made
the `toNat` part of its definition.
2024-02-22 19:25:01 +00:00
Sebastian Ullrich
8193af33e3 fix: split libInit_shared out of libleanshared (#3421)
Avoids hitting the Windows limit on symbols per shared library soon
2024-02-22 19:16:32 +00:00
Leonardo de Moura
53146db620 fix: zetaDelta := false regression (#3459)
See new test. It is a mwe for an issue blocking Mathlib.
2024-02-22 19:10:02 +00:00
Joachim Breitner
23d3ac4760 refactor: reduced unsed imports (#3464) 2024-02-22 18:12:57 +00:00
Joachim Breitner
5bbc54429f fix: improve error message when termination argument is too dependent (#3414)
this may help users when they face #2260

fixes #2260
2024-02-22 16:39:26 +00:00
Joachim Breitner
b27ab5e25d refactor: module MatcherApp.Transform (#3439)
PR #3432 will introduce more operations on `MatcherApp`, including somet
that have more dependencies.

This change prepares by introducing `Lean.Meta.Match.MatcherApp.Basic`
for the basic definition, and `Lean.Meta.MatcherApp.Transform` for the
transformations, currently `addArg` and `refineThrough`, but more to
come.
2024-02-22 16:16:26 +00:00
Scott Morrison
47595540bb chore: more List lemmas for auto (#3454) 2024-02-22 06:23:50 -08:00
Scott Morrison
aa0f43e9a1 chore: namespacing in solve_by_elim (#3453) 2024-02-22 06:23:50 -08:00
Alex Keizer
997ae402da feat: show basic properties of BitVec multiplication (#3445)
Show that multiplication of bitvectors is associative and commutative,
and show that it has 1#w as identity (both on the left and right).
2024-02-22 06:23:50 -08:00
Joe Hendrix
61c22c88d7 chore: address copyright inconsistencies (#3448) 2024-02-22 06:23:50 -08:00
Scott Morrison
629b7d0fdd chore: add bv_toNat attributes 2024-02-22 06:23:38 -08:00
Scott Morrison
46df6142a6 chore: update stage0 2024-02-22 06:23:26 -08:00
Scott Morrison
2b1a0371c6 feat: add bv_omega tactic 2024-02-22 06:23:13 -08:00
Siddharth
b6ed97bb3d feat: setup simp lemmas: 'msb -> getLsb -> decide ...' (#3436)
This is a follow up to 'https://github.com/leanprover/std4/pull/645',
where the simp lemmas were requested:
https://github.com/leanprover/std4/pull/645#issuecomment-1944862251

---

Note that @semorrison asked to use `(Fin.last _)` to index. Now that we
use a `Nat` to index `msb` , the pattern `(Fin.last _)` would not have
the width be automatically inferred. Therefore, I've changed the
definitions to use `Nat` for indexing.

---------

Co-authored-by: Siddharth Bhat Mala <sb2743@cl.cam.ac.uk>
Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-02-22 00:07:14 +00:00
Phil de Joux
9a970611ca doc: correct typo "can calls" (#3446)
Fixes a minor typo.
2024-02-21 22:31:02 +00:00
Joe Hendrix
6e821de11a chore: update stage0 2024-02-21 21:58:54 +01:00
Joe Hendrix
db3c1d4e7e chore: make server completion predicate not private 2024-02-21 21:58:54 +01:00
Leonardo de Moura
4d0c0e2328 fix: allow users to disable builtin simprocs in simp args (#3441) 2024-02-21 20:01:11 +00:00
Leonardo de Moura
e5d2cbceaa fix: structural equation proof generator (#3444)
See new test.
2024-02-21 19:42:39 +00:00
Leonardo de Moura
ddd6342737 fix: support for Fin and BitVec literal normalization (#3443) 2024-02-21 19:05:47 +00:00
Joe Hendrix
75272cb157 feat: BitVec.ofNatLt and updates to use it (#3430)
This PR is an effort to improve reasoning at the Nat level about
bitvectors and reduce of Fin and Nat.

It slightly tightens some proofs, but is generally aimed at reducing
inconsistencies between definitions at the Nat and Fin types in favor of
more consistently using Nat operations.

This ports leanprover/std4#664 to Lean core.

Here was the rational I provided in the discussion for
leanprover/std4#664:

It's mostly about consistency. If we use the same types and style in
definitions and proofs, there is less surprise when unfolding or
otherwise using definitions. We use some Nat based operations that
haven't been extended to Fin such as the bitwise operations, and I don't
want to pay the overhead of introducing a Fin version of every Bitvector
operation.
So this basically means Nat is preferred.

One argument potentially in favor of Fin is that we could reuse results
proven there, but that doesn't really seem to be the case so far.

A second argument is that we want to simplify expression to use more
canonical forms and we currently can pretty-print those operations
better using ofNat than ofFin. We could define the notations using ofFin
of course though, but that's additional operators that will show up in
expressions.
2024-02-21 18:02:56 +00:00
Leonardo de Moura
d55bab41bb feat: Int.toNat simproc (#3440) 2024-02-21 17:12:14 +00:00
Lean stage0 autoupdater
71cfbb26de chore: update stage0 2024-02-21 15:19:07 +00:00
David Thrane Christiansen
74e7886ce7 feat: custom error recovery in parser (#3413)
Adds a simple error-recovery mechanism to Lean's parser, similar to
those used in other combinator parsing libraries.

Lean itself isn't very amenable to error recovery with this mechanism,
as it requires global knowledge of the grammar in question to write
recovery rules that don't break backtracking or `<|>`. I only found a
few opportunities.

But for DSLs, this is really important. In particular, Verso parse
errors interacted very badly with Lean parse errors in a way that
required frequent "restart file" commands, but this mechanism allows me
to both recover from Verso parse errors and to have Lean skip the rest
of the file rather than repeatedly trying to parse it as Lean commands.
2024-02-21 14:29:54 +00:00
Leonardo de Moura
0fb936158b chore: explicit DecidableEq instance for BitVec (#3438) 2024-02-21 13:37:00 +00:00
Scott Morrison
cc8adfb2a5 feat: support for Fin in omega (#3427) 2024-02-21 13:09:38 +00:00
Leonardo de Moura
a0089d4667 fix: match pattern missing test 2024-02-21 05:14:26 -08:00
Scott Morrison
29b589a867 chore: add @[simp] to BitVec.toNat_mul (#3434) 2024-02-21 11:57:12 +00:00
Scott Morrison
f76bb2495b feat: omega handles shift operators, and normalises ground term exponentials (#3433)
This is a preliminary to a BitVec frontend for `omega`.
2024-02-21 11:55:58 +00:00
Joe Hendrix
89490f648a fix: address symm and label bugs from #3408 (#3429)
#3408 was somewhat large and didn't properly test the symm and label
attribute code after edits to the builtin versions.

This migrates the code for generating labeled attributes from Init back
to Lean so that the required definitions are in scope.

This also addresses a mistake in the symm elaborator that prevented symm
without location information from elaborating.

Both fixes have been tested on the Std test suite and successfully
passed.
2024-02-21 07:21:07 +00:00
Scott Morrison
6719af350f chore: remove mkAppN macro in omega (#3428) 2024-02-21 05:11:37 +00:00
Scott Morrison
3d8f73380e chore: simplify decide (b = true) and variants (#3426)
```
@[simp] theorem decide_eq_true {b : Bool} : decide (b = true) = b := by cases b <;> simp
@[simp] theorem decide_eq_false {b : Bool} : decide (b = false) = !b := by cases b <;> simp
@[simp] theorem decide_true_eq {b : Bool} : decide (true = b) = b := by cases b <;> simp
@[simp] theorem decide_false_eq {b : Bool} : decide (false = b) = !b := by cases b <;> simp
```
2024-02-21 04:30:25 +00:00
Scott Morrison
959ad98861 fix: bug in omega's elimination selection (#3425)
Silly bug that was resulting in unnecessary inexact eliminations. I'm
surprised this hasn't already been biting users.
2024-02-21 01:46:08 +00:00
Joe Hendrix
29244f32f6 chore: upstream solve_by_elim (#3408)
This upstreams the solve_by_elim tactic from Std.

It is a key tactic needed by library_search.
2024-02-21 01:16:04 +00:00
Scott Morrison
09cfcefb25 chore: upstream List.get?_append (#3424)
This suffices to get `lean-auto` off Std. (At least, `lake build` works.
Their test suite is [not
automated](https://github.com/leanprover-community/lean-auto/issues/21)?)
2024-02-20 23:53:41 +00:00
Sebastian Ullrich
c9aea32d3e chore: speedcenter: count max symbols in shared libraries (#3418) 2024-02-20 19:25:24 +00:00
Eric Wieser
07f490513c doc: fix confusing language in Expr.isProp (#3420)
`True` "is *a* `Prop`", but this function actually returns whether
something *is* `Prop`.
2024-02-20 16:08:28 +00:00
Leonardo de Moura
928f3e434e chore: add norm_cast_add_elim ne_eq
Recall that `add_elim` was a local command in Std
2024-02-20 07:00:47 -08:00
Leonardo de Moura
855a762bcb chore: update stage0 2024-02-20 07:00:47 -08:00
Leonardo de Moura
e1c176543a feat: add command norm_cast_add_elim 2024-02-20 07:00:47 -08:00
Leonardo de Moura
15be8fc2a6 fix: builtin_initialize at pushCastExt 2024-02-20 07:00:47 -08:00
Scott Morrison
28a02a8688 chore: upstream norm_cast attributes and tests 2024-02-20 07:00:47 -08:00
Adrien Champion
a898aa18f3 chore: add documentation for the String.iterator API (#3300)
Adds documentation to the `String.Iterator` API, mentored by
@eric-wieser and @david-christiansen

---------

Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-02-20 13:31:27 +00:00
Joachim Breitner
263629d140 chore: pr-release to suggest a git rebase command (#3417) 2024-02-20 13:06:06 +00:00
Henrik Böving
b598c0fea9 doc: prelude convention in Lean (#3416) 2024-02-20 12:11:57 +00:00
Sebastian Ullrich
d0fb48b4e4 fix: use builtin code action for "try this" 2024-02-20 12:48:19 +01:00
Sebastian Ullrich
79a9f6759a chore: update stage0 2024-02-20 12:48:19 +01:00
Sebastian Ullrich
f1a3169424 fix: [builtin_code_action_provider] 2024-02-20 12:48:19 +01:00
Scott Morrison
4a7c1ea439 chore: upstream simp? 2024-02-20 12:48:19 +01:00
Scott Morrison
15cbcae7b2 chore: typo (#3415) 2024-02-20 10:40:59 +00:00
Scott Morrison
ea665de453 chore: CI checks for copyright headers (#3412)
Hopefully this will fail until #3411 is merged.
2024-02-20 07:02:50 +00:00
Scott Morrison
8b8e001794 chore: add missing copyright headers (#3411) 2024-02-20 01:49:55 +00:00
Scott Morrison
35e374350c chore: upstream norm_cast tactic (#3322)
This is a quite substantial tactic.

It also includes the infamour `NatCast` typeclass (which I've equipped
with a module-doc). I wasn't at all sure where that should live, so it
is currently randomly in `Lean/Elan/Tactic/NatCast.lean`: presumably if
we're doing this it will go somewhere in `Init`.

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-02-19 17:49:17 -08:00
Leonardo de Moura
9e27e92eea chore: set literal notation (#3348)
Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-02-19 23:22:36 +00:00
Leonardo de Moura
489f2da711 feat: add simproc for BitVec.signExtend (#3409) 2024-02-19 15:15:37 -08:00
Leonardo de Moura
75d7bc0ef1 chore: disable test to fix build failure on Windows (#3410) 2024-02-19 15:15:26 -08:00
Leonardo de Moura
5d9552d66c feat: simprocs for BitVec (#3407) 2024-02-19 14:01:00 -08:00
Leonardo de Moura
067913bc36 chore: remove sorry 2024-02-19 13:01:44 -08:00
Leonardo de Moura
c23a35c472 chore: quick temporary fix 2024-02-19 12:53:25 -08:00
Leonardo de Moura
f64d14ea54 chore: update stage0 2024-02-19 12:47:04 -08:00
Leonardo de Moura
90b5a0011d feat: assume function application arguments occurring in local simp theorems have been annotated with no_index (#3406)
closes #2670
2024-02-19 12:43:34 -08:00
Scott Morrison
ca941249b9 chore: upstream Std.BitVec.* (#3400)
Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-02-19 12:43:34 -08:00
Sebastian Ullrich
94a9ab45ff chore: Nix CI: stop pushing to cachix (#3402) 2024-02-19 16:41:20 +00:00
Joe Hendrix
e2b3b34d14 feat: introduce native functions for Int.ediv / Int.emod (#3376)
These still need tests, but I thought I'd upstream so I can use
benchmarking and check for build errors.
2024-02-19 15:04:51 +00:00
Sebastian Ullrich
204b408df7 chore: remove noisy root code owners 2024-02-19 17:30:21 +01:00
Lean stage0 autoupdater
7545b85512 chore: update stage0 2024-02-19 15:51:18 +00:00
Sebastian Ullrich
1d66c32d5f fix: weaken builtin widget collision check 2024-02-19 15:45:01 +00:00
Scott Morrison
7f08975176 chore: upstream simpa (#3396) 2024-02-19 13:37:34 +00:00
Sebastian Ullrich
0e0ed9ccaf fix: broken trace tree on elab runtime exception (#3371) 2024-02-19 11:15:23 +00:00
Sebastian Ullrich
59bf220934 chore: update stage0 2024-02-19 12:37:19 +01:00
Sebastian Ullrich
032a2ecaa1 chore: update builtin_widget_module registration code 2024-02-19 12:33:23 +01:00
Joachim Breitner
da24708ba5 refactor: use isAppOfArity (#3394) 2024-02-19 09:24:11 +00:00
Scott Morrison
16757bb256 chore: upstream Std.Data.Fin.Iterate (#3392) 2024-02-19 04:29:45 +00:00
Scott Morrison
3f548edcd7 chore: upstream (most of) Std.Data.Nat.Lemmas (#3391)
When updating Std, be careful that not every lemma has been upstreamed,
so we need to be careful to only delete things that have already been
declared.
2024-02-19 03:47:49 +00:00
Scott Morrison
8758c0adf5 chore: upstream Std.Data.Bool (#3389) 2024-02-19 02:44:07 +00:00
Scott Morrison
b41499cec1 chore: upstream Std.Data.Fin.Basic (#3390) 2024-02-19 02:16:17 +00:00
Scott Morrison
88deb34ddb chore: upstream omega (#3367)
Co-authored-by: Joe Hendrix <joe@lean-fro.org>
2024-02-19 00:19:55 +00:00
Sebastian Ullrich
5e5bdfba1a fix: savePanelWidgetInfo on @[builtin_widget_module] (#3329) 2024-02-18 22:47:30 +00:00
Henrik Böving
23e49eb519 perf: add prelude to all Lean modules 2024-02-18 14:55:17 -08:00
Leonardo de Moura
5ce20ba160 chore: add link to issue 2024-02-18 14:19:01 -08:00
Leonardo de Moura
aa42fc07d3 test: for issue #2843
closes #2843
2024-02-18 14:14:55 -08:00
Leonardo de Moura
bc74e6eb38 chore: update RELEASES.md 2024-02-18 14:14:55 -08:00
Leonardo de Moura
52f1fcc498 chore: remove workaround 2024-02-18 14:14:55 -08:00
Leonardo de Moura
a6cdc333d5 chore: fix tests 2024-02-18 14:14:55 -08:00
Leonardo de Moura
58ed6b9630 chore: update stage0 2024-02-18 14:14:55 -08:00
Leonardo de Moura
cd9648a61e fix: dsimp zeta bug
Before the `zeta` / `zetaDelta` split, `dsimp` was performing `zeta`
by going inside of a `let`-expression, performing `zetaDelta`, and
then removing the unused `let`-expression.
2024-02-18 14:14:55 -08:00
Leonardo de Moura
55ce5d570c chore: add temporary workaround 2024-02-18 14:14:55 -08:00
Leonardo de Moura
ead14987bc chore: set zetaDelta := true at simp_wf 2024-02-18 14:14:55 -08:00
Leonardo de Moura
834b515592 chore: update stage0 2024-02-18 14:14:55 -08:00
Leonardo de Moura
9fe72c5f95 chore: set zetaDelta := false by default in the simplifier 2024-02-18 14:14:55 -08:00
Leonardo de Moura
77de817960 chore: update stage0 2024-02-18 14:14:55 -08:00
Leonardo de Moura
457d33d660 feat: configuration options zeta and zetaDelta
TODO: bootstrapping issues, set `zetaDelta := false` in the simplifier.
2024-02-18 14:14:55 -08:00
Leonardo de Moura
b882ebcf4a chore: update stage0 2024-02-18 14:14:55 -08:00
Leonardo de Moura
602b1a0d15 feat: add zetaDelta configuration option 2024-02-18 14:14:55 -08:00
Joachim Breitner
17c7cb0e1c feat: conv => fun (#3240)
Given a target
```
| f a b
```
the new conv tactic
```
conv => fun
```
turns it into
```
| f a
```
and `arg 0` turns it into
```
| f
```

Fixes #3239
2024-02-18 12:02:25 +00:00
Scott Morrison
e206e53f4e chore: add @[simp] to Nat.sub_add_cancel (#3378) 2024-02-18 06:48:10 +00:00
Kyle Miller
d569ed4e5f feat: make loose fvars pretty print as _fvar.123 instead of _uniq.123 (#3380)
Loose fvars are never supposed to be pretty printed, but having them
print with "fvar" in the name can help with debugging broken tactics and
elaborators.

Metaprogramming users often do not realize at first that `_uniq.???` in
pretty printing output refers to fvars not in the current local context.
2024-02-18 01:53:37 +00:00
Kyle Miller
433c4d22c2 fix: exposeRelevantUniverses was inserting the whole expression into itself
This bug appeared in c9db8619f1
2024-02-17 17:53:19 -08:00
Leonardo de Moura
6383af0595 chore: update stage0 2024-02-17 17:51:24 -08:00
Leonardo de Moura
c8236ccd47 chore: basic simprocs for String 2024-02-17 17:51:24 -08:00
Leonardo de Moura
559a18874c chore: simprocs for Eq 2024-02-17 17:51:24 -08:00
Leonardo de Moura
3dcc8cab3e feat: simprocs for Char.val, default char, and Char.ofNatAux 2024-02-17 17:51:24 -08:00
Leonardo de Moura
fb18ef3688 feat: simprocs for UInt??.ofNatCore and UInt??.toNat 2024-02-17 17:51:24 -08:00
Leonardo de Moura
3e5695e07e feat: simprocs for Char (#3382) 2024-02-17 20:36:51 +00:00
Leonardo de Moura
61a76a814f feat: delaborator for Char literals (#3381) 2024-02-17 12:19:40 -08:00
Arthur Adjedj
0c92d17792 fix: instantiate the types of inductives with the right parameters (#3246)
Closes #3242
2024-02-17 16:52:28 +00:00
Joachim Breitner
d536534c4d refactor: drop CasesOnApp, use MatcherApp (#3369)
in all uses of `CasesOnApp`, we treat `MatcherApp`s the same way,
dupliating a fair amount of relatively hairy code (and there is more to
come).

However, the `MatcherApp` abstraction is perfectly capable of
also representing `casesOn` applications, at least for the use cases
encountered so far.

So lets just (optionally) include `casesOn` applications when looking
for matchers,
and remove the `CasesOnApp` abstraction completely.
2024-02-17 15:25:32 +00:00
Leonardo de Moura
97e7e668d6 chore: pp.proofs.withType is now false by default (#3379)
`pp.proofs.withType := true` often produces too much noise in the info
view.
2024-02-17 15:09:24 +00:00
Sebastian Ullrich
dda88c9926 feat: infoview.maxTraceChildren (#3370)
Incrementally unveil trace children for excessively large nodes to
improve infoview rendering time, adjust particularly chatty
`simp.ground` trace to make use of it.
2024-02-17 14:04:46 +00:00
Leonardo de Moura
ef9a6bb839 fix: an equation lemma with autoParam arguments fails to rewrite (#3316)
closes #2243
2024-02-17 13:42:34 +00:00
Leonardo de Moura
baa9fe5932 fix: simp gets stuck on autoParam (#3315)
closes #2862
2024-02-17 13:42:19 +00:00
Leonardo de Moura
368326fb48 fix: simp fails when custom discharger makes no progress (#3317)
closes #2634
2024-02-17 13:42:04 +00:00
Leonardo de Moura
678797b67b fix: simp fails to discharge autoParam premises even when it can reduce them to True (#3314)
closes #3257
2024-02-17 13:41:48 +00:00
Mac Malone
496a8d578e fix: lake: open config trace as read-only first & avoid deadlock (#3254)
Lake previously opened the configuration trace as read-write even if it
does not update the configuration. This meant it failed if the trace was
read-only. With this change, it now first acquires a read-only handle
and then, if and only if it determines the need for a reconfigure, does
it re-open the file with a read-write handle. Also, this change fixes a
potential deadlock (Lake will error instead) and generally clarifies the
trace locking code.
2024-02-17 04:20:14 +00:00
Mac Malone
3fb7262fe0 fix: cloud release trace & lake build :release errors (#3248)
Fixes a bug with Lake cloud releases where a cloud release would produce
a different trace if the package was the root of the workspace versus a
dependency. Also, an explicit fetch of a cloud release (e.g., via `lake
build :release`) will now error out with a non-zero exit code if it
fails to find, download, and unpack a release.
2024-02-17 00:18:10 +00:00
Joe Hendrix
8f010a6115 fix: liasolver benchmark bug introduced by #3364 (#3372)
This fixes a rounded division/mod bug introduced by the change in
semantics from Int.div to Int.mod in #3364.
2024-02-16 23:39:26 +00:00
Joachim Breitner
089cd50d00 refactor: let MatcherApp.addArg? check if argument was refined (#3368)
Previously, `CasesOn.addArg?` would do that check inline, while
`MatcherApp.addArg?` would do it after the fact.

Now `MatcherApp.addArg?` uses the same idiom.

Also, makes both `addArg?` always fail if the argument was not refined.

The work on functional induction principles calls for more unification
between the handling of `CasesOnApp` and `MatcherApp`, so this is a step
in that direction.
2024-02-16 15:35:19 +00:00
Scott Morrison
18afefda96 chore: upstream basic statements about inequalities (#3366) 2024-02-16 05:42:38 +00:00
Joe Hendrix
06e21faecd chore: upstream Std.Data.Int.Init modules (#3364)
This is pretty big PR that upstreams all of Std.Data.Int.Init in one go.

So far lemmas have seen minimal changes needed to adapt to Lean core
environment.

---------

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-02-16 03:58:23 +00:00
Scott Morrison
c9f27c36a0 chore: upstream false_or_by_contra tactic (#3363)
Changes the goal to `False`, retaining as much information as possible:

* If the goal is `False`, do nothing.
* If the goal is an implication or a function type, introduce the
argument and restart.
  (In particular, if the goal is `x ≠ y`, introduce `x = y`.)
* Otherwise, for a propositional goal `P`, replace it with `¬ ¬ P`
(attempting to find a `Decidable` instance, but otherwise falling back
to working classically)
  and introduce `¬ P`.
* For a non-propositional goal use `False.elim`.
2024-02-16 03:58:10 +00:00
Scott Morrison
c9cba33f57 chore: upstream Expr.nat? and int? for recognising 'normal form' numerals (#3360)
`nat?` checks if an expression is a "natural number in normal form",
i.e. of the form `OfNat n`, where `n` matches `.lit (.natVal n)` for
some `n`.
and if so returns `n`.
2024-02-16 03:31:22 +00:00
Scott Morrison
84bd563cff chore: upstream Std's material on Ord and Ordering (#3365) 2024-02-16 02:57:47 +00:00
Scott Morrison
73524e37ae chore: upstream exfalso (#3361) 2024-02-16 02:21:32 +00:00
Scott Morrison
229f16f421 chore: upstream MVarId.applyConst (#3362)
Helper function for applying a constant to the goal, with fresh universe
metavariables.
2024-02-16 02:08:47 +00:00
Scott Morrison
eaf44d74ae chore: upstream Option material from Std (#3356) 2024-02-16 02:05:18 +00:00
Scott Morrison
6fc3ea7790 chore: upstream Expr.getAppFnArgs (#3359)
This is a widely used helper function in Std/Mathlib when matching on
expressions.

I've reordered some definitions to keep things together. This
introduces:
```
/-- Return the function (name) and arguments of an application. -/
def getAppFnArgs (e : Expr) : Name × Array Expr :=
  withApp e λ e a => (e.constName, a)
```
and 
```
/-- If the expression is a constant, return that name. Otherwise return `Name.anonymous`. -/
def constName (e : Expr) : Name :=
  e.constName?.getD Name.anonymous
```
2024-02-16 01:51:59 +00:00
Scott Morrison
a4e27d3090 chore: upstream HashSet.merge (#3357) 2024-02-16 01:38:16 +00:00
Joe Hendrix
1d9074c524 chore: upstream NatCast and IntCast (#3347)
This upstreams NatCast and IntCast alone independent of norm_cast in
#3322.

This will allow more efficiently upstreaming parts of Std.Data.Int
relevant for omega.

---------

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-02-16 00:54:22 +00:00
Kyle Miller
e29d75a961 feat: have pp.proofs use for omission (#3241)
By having the `pp.proofs` feature use `⋯` when omitting proofs, when
users copy/paste terms from the InfoView the elaborator can give an
error message explaining why the term cannot be elaborated.

Also adds `pp.proofs.threshold` option to allow users to pretty print
shallow proof terms. By default, only atomic proof terms are pretty
printed.

This adjustment was suggested in PR #3201, which added `⋯` and the
related `pp.deepTerms` option.
2024-02-15 21:49:41 +00:00
Kyle Miller
8aab74e65d fix: make withOverApp annotate the expression position and register TermInfo (#3327)
This makes it so that when `withOverApp` is handling overapplied
functions, the term produced by the supplied delaborator is hoverable in
the Infoview.
2024-02-15 17:40:54 +00:00
Sebastian Ullrich
4e58b428e9 doc: add Kyle Miller as delaborator code owner 2024-02-15 17:42:57 +01:00
Lean stage0 autoupdater
271ae5b8e5 chore: update stage0 2024-02-15 12:32:00 +00:00
Leonardo de Moura
a14bbbffb2 chore: add [ext] basic theorems, add test 2024-02-15 13:26:01 +01:00
Scott Morrison
5a95f91fae chore: update stage0 2024-02-15 13:26:01 +01:00
Scott Morrison
11727a415b chore: upstream ext
and_intros and subst_eqs are not builtin

clarify failure modes

Clarify docString of extCore

clarify

chore: builtin `subst_eqs` tactic

chore: builtin `ext`
2024-02-15 13:26:01 +01:00
Sebastian Ullrich
90a516de09 chore: avoid libleanshared symbol limit (#3346) 2024-02-15 11:39:44 +00:00
Scott Morrison
ae524d465f chore: a missing List lemma in Init (#3344) 2024-02-15 08:55:48 +00:00
Scott Morrison
9a3f0f1909 chore: upstream Std.Data.Array.Init.Lemmas (#3343) 2024-02-15 17:50:07 +11:00
Scott Morrison
fae5b2e87c chore: upstream Std.Data.List.Init.Lemmas (#3341) 2024-02-15 03:19:23 +00:00
Leonardo de Moura
2bd187044f chore: builtin haveI and letI 2024-02-15 14:33:36 +11:00
Scott Morrison
144c1bbbaf chore: update stage0 2024-02-15 14:33:36 +11:00
Scott Morrison
98085661c7 chore: upstream haveI tactic
chore: `haveI` and `letI` builtin parsers
2024-02-15 14:33:36 +11:00
Scott Morrison
9cea1a503e chore: upstream Std.Data.Prod.Lex (#3338) 2024-02-15 02:47:08 +00:00
Joe Hendrix
25147accc8 chore: upstream set notation (#3339)
This upstream Std Set notation except for [set
literals](1b4e6926f0/Std/Classes/SetNotation.lean (L115-L131)).
2024-02-15 02:08:45 +00:00
Scott Morrison
6048ba9832 chore: upstream Std.Classes.LawfulMonad (except SatisfiesM) (#3340) 2024-02-15 01:52:02 +00:00
Scott Morrison
33bb87cd1d chore: upstream Std.Data.Fin.Init.Lemmas (#3337) 2024-02-15 01:50:47 +00:00
Scott Morrison
4aa62a6a9c chore: upstream Std.Data.List.Init.Basic (#3335) 2024-02-15 01:50:33 +00:00
Joe Hendrix
eebdfdf87a chore: upstream of Std.Data.Nat.Init (#3331) 2024-02-15 00:18:41 +00:00
Leonardo de Moura
01c9f4c783 fix: run_meta macro (#3334) 2024-02-15 00:12:45 +00:00
Kyle Miller
a706c3b89a feat: delaboration collapses parent projections (#3326)
When projection functions are delaborated, intermediate parent
projections are no longer printed. For example, rather than pretty
printing as `o.toB.toA.x` with these `toB` and `toA` parent projections,
it pretty prints as `o.x`.

This feature is being upstreamed from mathlib.
2024-02-14 23:44:48 +00:00
Scott Morrison
329e00661a chore: upstream Std.Util.ExtendedBinders (#3320)
This is not a complete upstreaming of that file (it also supports `∀ᵉ (x
< 2) (y < 3), p x y` as shorthand for `∀ x < 2, ∀ y < 3, p x y`, but I
don't think we need this; it is used in Mathlib).

Syntaxes still need to be made built-in.

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-02-14 11:36:00 +00:00
Joe Hendrix
8b0dd2e835 chore: upstream Std.Logic (#3312)
This will collect definitions from Std.Logic

---------

Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-02-14 09:40:55 +00:00
Leonardo de Moura
88a5d27d65 chore: upstream run_cmd and fixes bugs (#3324)
Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-02-14 04:15:28 +00:00
Scott Morrison
232b2b6300 chore: upstream replace tactic (#3321)
Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-02-14 01:53:25 +00:00
Scott Morrison
fdc64def1b feat: upstream 'Try this:' widgets (#3266)
There is a test file in Std that should later be reunited with this
code.

---------

Co-authored-by: Sebastian Ullrich <sebasti@nullri.ch>
2024-02-13 21:58:36 +00:00
Leonardo de Moura
644d4263f1 fix: #eval command was leaking auxiliary declarations into the environment (#3323) 2024-02-13 21:44:52 +00:00
Mario Carneiro
56d703db8e fix: trailing whitespace in location formatter (#3318)
This causes problems when used in conjunction with `#guard_msgs` (which
checks whitespace) and trailing whitespace removal. Discovered by
@PatrickMassot in verbose-lean4.
2024-02-13 15:53:29 +00:00
Henrik Böving
50d661610d perf: LLVM backend, put all allocas in the first BB to enable mem2reg (#3244)
Again co-developed with @bollu.

Based on top of: #3225 

While hunting down the performance discrepancy on qsort.lean between C
and LLVM we noticed there was a single, trivially optimizeable, alloca
(LLVM's stack memory allocation instruction) that had load/stores in the
hot code path. We then found:
https://groups.google.com/g/llvm-dev/c/e90HiFcFF7Y.

TLDR: `mem2reg`, the pass responsible for getting rid of allocas if
possible, only triggers on an alloca if it is in the first BB. The
allocas of the current implementation get put right at the location
where they are needed -> they are ignored by mem2reg.

Thus we decided to add functionality that allows us to push all allocas
up into the first BB.
We initially wanted to write `buildPrologueAlloca` in a `withReader`
style so:
1. get the current position of the builder
2. jump to first BB and do the thing
3. revert position to the original

However the LLVM C API does not expose an option to obtain the current
position of an IR builder. Thus we ended up at the current
implementation which resets the builder position to the end of the BB
that the function was called from. This is valid because we never
operate anywhere but the end of the current BB in the LLVM emitter.

The numbers on the qsort benchmark got improved by the change as
expected, however we are not fully there yet:
```
C:
Benchmark 1: ./qsort.lean.out 400
  Time (mean ± σ):      2.005 s ±  0.013 s    [User: 1.996 s, System: 0.003 s]
  Range (min … max):    1.993 s …  2.036 s    10 runs

LLVM before aligning the types
Benchmark 1: ./qsort.lean.out 400
  Time (mean ± σ):      2.151 s ±  0.007 s    [User: 2.146 s, System: 0.001 s]
  Range (min … max):    2.142 s …  2.161 s    10 runs

LLVM after aligning the types
Benchmark 1: ./qsort.lean.out 400
  Time (mean ± σ):      2.073 s ±  0.011 s    [User: 2.067 s, System: 0.002 s]
  Range (min … max):    2.060 s …  2.097 s    10 runs

LLVM after this
Benchmark 1: ./qsort.lean.out 400
  Time (mean ± σ):      2.038 s ±  0.009 s    [User: 2.032 s, System: 0.001 s]
  Range (min … max):    2.027 s …  2.052 s    10 runs
```

Note: If you wish to merge this PR independently from its predecessor,
there is no technical dependency between the two, I'm merely stacking
them so we can see the performance impacts of each more clearly.
2024-02-13 14:54:40 +00:00
Eric Wieser
0554ab39aa doc: Add a docstring to Simp.Result and its fields (#3319) 2024-02-13 13:57:24 +00:00
Scott Morrison
3a6ebd88bb chore: upstream repeat/split_ands/subst_eqs (#3305)
Small tactics used in the implementation of `ext`.

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-02-13 12:21:14 +00:00
Henrik Böving
06f73d621b fix: type mismatches in the LLVM backend (#3225)
Debugged and authored in collaboration with @bollu.

This PR fixes several performance regressions of the LLVM backend
compared to the C backend
as described in #3192. We are now at the point where some benchmarks
from `tests/bench` achieve consistently equal and sometimes ever so
slightly better performance when using LLVM instead of C. However there
are still a few testcases where we are lacking behind ever so slightly.

The PR contains two changes:
1. Using the same types for `lean.h` runtime functions in the LLVM
backend as in `lean.h` it turns out that:
a) LLVM does not throw an error if we declare a function with a
different type than it actually has. This happened on multiple occasions
here, in particular when the function used `unsigned`, as it was
wrongfully assumed to be `size_t` sized.
b) Refuses to inline a function to the call site if such a type mismatch
occurs. This means that we did not inline important functionality such
as `lean_ctor_set` and were thus slowed down compared to the C backend
which did this correctly.
2. While developing this change we noticed that LLVM does treat the
following as invalid: Having a function declared with a certain type but
called with integers of a different type. However this will manifest in
completely nonsensical errors upon optimizing the bitcode file through
`leanc` such as:
```
error: Invalid record (Producer: 'LLVM15.0.7' Reader: 'LLVM 15.0.7')
```
Presumably because the generate .bc file is invalid in the first place.
Thus we added a call to `LLVMVerifyModule` before serializing the module
into a bitcode file. This ended producing the expected type errors from
LLVM an aborting the bitcode file generation as expected.

We manually checked each function in `lean.h` that is mentioned in
`EmitLLVM.lean` to make sure that all of their types align correctly
now.

Quick overview of the fast benchmarks as measured on my machine, 2 runs
of LLVM and 2 runs of C to get a feeling for how far the averages move:
- binarytrees: basically equal performance
- binarytrees.st: basically equal performance
- const_fold: equal if not slightly better for LLVM
- deriv: LLVM has 8% more instructions than C but same wall clock time
- liasolver: basically equal performance
- qsort: LLVM is slower by 7% instructions, 4% time. We have identified
why the generated code is slower (there is a store/load in a hot loop in
LLVM that is not in C) but not figured out why that happens/how to
address it.
- rbmap: LLVM has 3% less instructions and 13% less wall-clock time than
C (woop woop)
- rbmap_1 and rbmap_10 show similar behavior
- rbmap_fbip: LLVM has 2% more instructions but 2% better wall time
- rbmap_library: equal if not slightly better for LLVM
- unionfind: LLVM has 5% more instructions but 4% better wall time

Leaving out benchmarks related to the compiler itself as I was too lazy
to keep recompiling it from scratch until we are on a level with C.

Summing things up, it appears that LLVM has now caught up or surpassed
the C backend in the microbenchmarks for the most part. Next steps from
our side are:
- trying to win the qsort benchmark
- figuring out why/how LLVM runs more instructions for less wall-clock
time. My current guesses would be measurement noise and/or better use of
micro architecture?
- measuring the larger benchmarks as well
2024-02-13 10:57:35 +00:00
Scott Morrison
c27474341e chore: upstream change tactic (#3308)
We previously had the syntax for `change` and `change at`, but no
implementation.

This moves Kyle's implementation from Std.

This also changes the `changeLocalDecl` function to push nodes to the
infotree about FVar aliases.

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-02-13 04:47:11 +00:00
Scott Morrison
27b962f14d chore: upstream liftCommandElabM (#3304)
These are used in the implementation of `ext`.
2024-02-13 04:17:19 +00:00
Scott Morrison
2032ffa3fc chore: DiscrTree helper functions (#3303)
`DiscrTree` helper functions from `Std`, used in `ext`, `exact?`, and
`aesop`.

(There are a few more to follow later, with other Std dependencies.)
2024-02-13 03:46:31 +00:00
Scott Morrison
c424d99cc9 chore: upstream left/right tactics (#3307)
Co-authored-by: Joachim Breitner <mail@joachim-breitner.de>
2024-02-13 03:45:59 +00:00
Mario Carneiro
fbedb79b46 fix: add_decl_doc should check that declarations are local (#3311)
This was causing a panic previously, [reported on
Zulip](https://leanprover.zulipchat.com/#narrow/stream/287929-mathlib4/topic/CI.20errors.20that.20are.20not.20local.20errors/near/420986393).
2024-02-12 12:04:51 +00:00
Eric Wieser
1965a022eb doc: fix typos around inductiveCheckResultingUniverse (#3309)
The unpaired backtick was causing weird formatting in vscode doc hovers.

Also closes an unpaired `(` in an error message.
2024-02-12 10:11:50 +00:00
Scott Morrison
90b08ef22e feat: upstream guard_expr (#3297)
Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-02-11 23:25:04 +00:00
Wojciech Nawrocki
66e8cb7966 doc: implicit type arguments are indexed in the discrtree (#3301)
A small fix to the `DiscrTree` documentation to reflect the fact that
implicit type arguments *are* indexed and do not become `star` or
`other`. The following is a reproduction:
```lean
import Lean
open Lean Meta Elab Tactic

elab "test_tac" t:term : tactic => do
  Tactic.withMainContext do
    let e ← Term.elabTerm t none
    let a : DiscrTree Nat ← DiscrTree.empty.insert e 1 {}
    logInfo m!"{a}"

example (α : Type) (ringAdd : Add α) : True := by
  /- (Add.add => (node (Nat => (node (* => (node (0 => (node (1 => (node #[1])))))))))) -/
  test_tac @Add.add Nat instAddNat 0 1
  /- (Add.add => (node (_uniq.1154 => (node (* => (node ( => (node ( => (node #[1])))))))))) -/
  test_tac @Add.add α ringAdd ?_ ?_
```
2024-02-11 21:42:54 +00:00
Scott Morrison
4718af5474 chore: upstream rcases (#3292)
This moves the `rcases` and `obtain` tactics from Std, and makes them
built-in tactics.

We will separately move the test cases from Std after #3297
(`guard_expr`).

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-02-10 05:22:02 +00:00
Leonardo de Moura
c138801c3a chore: rwa tactic macro (#3299) 2024-02-10 04:59:24 +00:00
Leonardo de Moura
5b4c24ff97 chore: add nomatch tactic (#3294) 2024-02-10 04:59:06 +00:00
Leonardo de Moura
1cb7450f40 fix: nomatch regression (#3296) 2024-02-10 04:58:48 +00:00
Leonardo de Moura
02d1ebb564 fix: extended coe notation and delaborator (#3295) 2024-02-10 04:58:28 +00:00
Lean stage0 autoupdater
488bfe2128 chore: update stage0 2024-02-09 12:46:12 +00:00
Sebastian Ullrich
55402a5899 feat: add [builtin_code_action_provider] (#3289) 2024-02-09 11:51:40 +00:00
Sebastian Ullrich
659218cf17 feat: add [builtin_widget_module] (#3288) 2024-02-09 11:20:46 +00:00
Scott Morrison
904239ae61 feat: upstream some Syntax/Position helper functions used in code actions in Std (#3260)
Co-authored-by: David Thrane Christiansen <david@davidchristiansen.dk>
2024-02-09 10:50:19 +00:00
Sebastian Ullrich
b548b4faae refactor: make Promise implementation opaque (#3273)
This follows the standard `Ref` recipe and moves the `unsafeCast` into
C++
2024-02-09 10:43:41 +00:00
Scott Morrison
a7364499d2 chore: update line numbers in test after rebase 2024-02-09 10:05:54 +01:00
Leonardo de Moura
003835111d chore: fix tests 2024-02-09 18:23:46 +11:00
Scott Morrison
61a8695ab1 chore: update stage0 2024-02-09 18:23:46 +11:00
Leonardo de Moura
127214bd18 chore: cleanup and move unsafe term elaborator to BuiltinNotation 2024-02-09 18:23:46 +11:00
Scott Morrison
b1944b662c chore: update stage0 2024-02-09 18:23:46 +11:00
Leonardo de Moura
a17832ba14 chore: add unsafe term builtin parser 2024-02-09 18:23:46 +11:00
Scott Morrison
561ac09d61 chore: make mkAuxName private, add comment about alternatives 2024-02-09 18:23:46 +11:00
Scott Morrison
f68429d3a7 chore: move syntax to Init/Notation, make builtin_term_elab 2024-02-09 18:23:46 +11:00
Scott Morrison
a58232b820 core: upstream Std.Util.TermUnsafe 2024-02-09 18:23:46 +11:00
Scott Morrison
696b08dca2 chore: upstream Std.Tactic.CoeExt to Lean.Elab.CoeExt (#3280)
Moves the `@[coe]` attribute and associated elaborators/delaborators
from Std to Lean.

---------

Co-authored-by: Leonardo de Moura <leomoura@amazon.com>
2024-02-09 04:55:49 +00:00
Scott Morrison
3a63b72eea chore: update stage0 2024-02-09 15:56:57 +11:00
Leonardo de Moura
9c160b8030 feat: nofun tactic and term
closes #3279
2024-02-09 15:56:57 +11:00
Scott Morrison
4bd75825b4 chore: update stage0 2024-02-09 15:56:57 +11:00
Leonardo de Moura
709e9909e7 feat: add nofun term parser
This new syntax suggested by @semorrison for the `fun.` Std macro.
2024-02-09 15:56:57 +11:00
Scott Morrison
83dd720337 chore: upstream MetavarContext helpers (#3284)
These are from Std, but mostly used in Aesop.
2024-02-09 03:58:10 +00:00
Scott Morrison
ac631f4736 feat: allow overriding getSimpTheorems in mkSimpContext (#3281)
The `push_cast` tactic in Std currently uses a copy-paste version of
`mkSimpContext` that allows overriding `getSimpTheorems`. However it has
been diverging from the version in Lean.

This is one way of generalizing `mkSimpContext` in Lean to allow what is
needed downstream., but I'm not at all set on this one. As far as I can
see there are no other tactics currently using this.

`push_cast` itself just replaces `getSimpTheorems` with
`pushCastExt.getTheorems`, where `pushCastExt` is a simp extension. If
there is another approach that suits that situation it would be fine.

I've tested that the change in this PR works downstream.
2024-02-09 03:57:40 +00:00
Leonardo de Moura
1f547225d1 feat: nary nomatch (#3285)
Base for https://github.com/leanprover/lean4/pull/3279

---------

Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
2024-02-09 00:28:34 +00:00
Leonardo de Moura
09a43990aa refactor: move if-then-else tactic to Init 2024-02-09 09:57:57 +11:00
Leonardo de Moura
819848a0db chore: update stage0 2024-02-09 09:57:57 +11:00
Leonardo de Moura
8f8b0a8322 chore: fix proofs and test 2024-02-09 09:57:57 +11:00
Leonardo de Moura
9f633dcba2 chore: add register_parser_alias for matchRhs 2024-02-09 09:57:57 +11:00
Leonardo de Moura
cd4c7e4c35 refactor: move by_cases to Init/Classical.lean 2024-02-09 09:57:57 +11:00
Scott Morrison
9908823764 chore: upstream Std.Tactic.ByCases 2024-02-09 09:57:57 +11:00
Joe Hendrix
3e313d38f4 chore: upstream Std.Data.Array.Init.Basic (#3282)
This migrates the handful of array operations in
[Std.Data.Array.Init.Basic](https://github.com/leanprover/std4/blob/main/Std/Data/Array/Init/Basic.lean).
2024-02-08 19:30:47 +00:00
Scott Morrison
1b101a3d43 chore: upstream Std.Lean.Tactic (#3278)
A simple one, a small variant on `evalTacticAt`.

Perhaps a rename is in order?
2024-02-08 19:30:08 +00:00
Joe Hendrix
adcec8e67a chore: upstream Divides class and syntax (#3283)
This just upstreams the class and notation. Instances will be provided
with Nat/Int upstream
2024-02-08 08:09:02 +00:00
Scott Morrison
86d032ebf9 chore: upstream Std.Lean.LocalContext (#3275) 2024-02-08 07:43:25 +00:00
3740 changed files with 99432 additions and 16321 deletions

View File

@@ -9,9 +9,15 @@ assignees: ''
### Prerequisites
* [ ] Put an X between the brackets on this line if you have done all of the following:
* Check that your issue is not already [filed](https://github.com/leanprover/lean4/issues).
* Reduce the issue to a minimal, self-contained, reproducible test case. Avoid dependencies to mathlib4 or std4.
Please put an X between the brackets as you perform the following steps:
* [ ] Check that your issue is not already filed:
https://github.com/leanprover/lean4/issues
* [ ] Reduce the issue to a minimal, self-contained, reproducible test case.
Avoid dependencies to Mathlib or Batteries.
* [ ] Test your test case against the latest nightly release, for example on
https://live.lean-lang.org/#project=lean-nightly
(You can also use the settings there to switch to “Lean nightly”)
### Description
@@ -33,8 +39,8 @@ assignees: ''
### Versions
[Output of `#eval Lean.versionString` or of `lean --version` in the folder that the issue occured in]
[OS version]
[Output of `#eval Lean.versionString`]
[OS version, if not using live.lean-lang.org.]
### Additional Information

26
.github/workflows/check-prelude.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Check for modules that should use `prelude`
on: [pull_request]
jobs:
check-prelude:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# the default is to use a virtual merge commit between the PR and master: just use the PR
ref: ${{ github.event.pull_request.head.sha }}
sparse-checkout: src/Lean
- name: Check Prelude
run: |
failed_files=""
while IFS= read -r -d '' file; do
if ! grep -q "^prelude$" "$file"; then
failed_files="$failed_files$file\n"
fi
done < <(find src/Lean -name '*.lean' -print0)
if [ -n "$failed_files" ]; then
echo -e "The following files should use 'prelude':\n$failed_files"
exit 1
fi

57
.github/workflows/check-stage0.yml vendored Normal file
View File

@@ -0,0 +1,57 @@
name: Check for stage0 changes
on:
merge_group:
pull_request:
jobs:
check-stage0-on-queue:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
filter: blob:none
fetch-depth: 0
- name: Find base commit
if: github.event_name == 'pull_request'
run: echo "BASE=$(git merge-base origin/${{ github.base_ref }} HEAD)" >> "$GITHUB_ENV"
- name: Identify stage0 changes
run: |
git diff "${BASE:-HEAD^}..HEAD" --name-only -- stage0 |
grep -v -x -F $'stage0/src/stdlib_flags.h\nstage0/src/lean.mk.in' \
> "$RUNNER_TEMP/stage0" || true
if test -s "$RUNNER_TEMP/stage0"
then
echo "CHANGES=yes" >> "$GITHUB_ENV"
else
echo "CHANGES=no" >> "$GITHUB_ENV"
fi
shell: bash
- if: github.event_name == 'pull_request'
name: Set label
uses: actions/github-script@v7
with:
script: |
const { owner, repo, number: issue_number } = context.issue;
if (process.env.CHANGES == 'yes') {
await github.rest.issues.addLabels({ owner, repo, issue_number, labels: ['changes-stage0'] }).catch(() => {});
} else {
await github.rest.issues.removeLabel({ owner, repo, issue_number, name: 'changes-stage0' }).catch(() => {});
}
- if: env.CHANGES == 'yes'
name: Report changes
run: |
echo "Found changes to stage0/, please do not merge using the merge queue." | tee "$GITHUB_STEP_SUMMARY"
# shellcheck disable=SC2129
echo '```' >> "$GITHUB_STEP_SUMMARY"
cat "$RUNNER_TEMP/stage0" >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
- if: github.event_name == 'merge_group' && env.CHANGES == 'yes'
name: Fail when on the merge queue
run: exit 1

View File

@@ -6,7 +6,6 @@ on:
tags:
- '*'
pull_request:
types: [opened, synchronize, reopened, labeled]
merge_group:
schedule:
- cron: '0 7 * * *' # 8AM CET/11PM PT
@@ -21,8 +20,10 @@ jobs:
configure:
runs-on: ubuntu-latest
outputs:
# Should we run only a quick CI? Yes on a pull request without the full-ci label
quick: ${{ steps.set-quick.outputs.quick }}
# 0: PRs without special label
# 1: PRs with `merge-ci` label, merge queue checks, master commits
# 2: PRs with `release-ci` label, releases (incl. nightlies)
check-level: ${{ steps.set-level.outputs.check-level }}
# The build matrix, dynamically generated here
matrix: ${{ steps.set-matrix.outputs.result }}
# Should we make a nightly release? If so, this output contains the lean version string, else it is empty
@@ -39,157 +40,6 @@ jobs:
RELEASE_TAG: ${{ steps.set-release.outputs.RELEASE_TAG }}
steps:
- name: Run quick CI?
id: set-quick
env:
quick: ${{
github.event_name == 'pull_request' && !contains( github.event.pull_request.labels.*.name, 'full-ci')
}}
run: |
echo "quick=${{env.quick}}" >> "$GITHUB_OUTPUT"
- name: Configure build matrix
id: set-matrix
uses: actions/github-script@v7
with:
script: |
const quick = ${{ steps.set-quick.outputs.quick }};
console.log(`quick: ${quick}`)
let matrix = [
{
// portable release build: use channel with older glibc (2.27)
"name": "Linux LLVM",
"os": "ubuntu-latest",
"release": false,
"quick": false,
"shell": "nix-shell --arg pkgsDist \"import (fetchTarball \\\"channel:nixos-19.03\\\") {{}}\" --run \"bash -euxo pipefail {0}\"",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst",
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*",
"binary-check": "ldd -v",
// foreign code may be linked against more recent glibc
// reverse-ffi needs to be updated to link to LLVM libraries
"CTEST_OPTIONS": "-E 'foreign|leanlaketest_reverse-ffi'",
"CMAKE_OPTIONS": "-DLLVM=ON -DLLVM_CONFIG=${GITHUB_WORKSPACE}/build/llvm-host/bin/llvm-config"
},
{
"name": "Linux release",
"os": "ubuntu-latest",
"release": true,
"quick": true,
"shell": "nix-shell --arg pkgsDist \"import (fetchTarball \\\"channel:nixos-19.03\\\") {{}}\" --run \"bash -euxo pipefail {0}\"",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst",
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*",
"binary-check": "ldd -v",
// foreign code may be linked against more recent glibc
"CTEST_OPTIONS": "-E 'foreign'"
},
{
"name": "Linux",
"os": "ubuntu-latest",
"check-stage3": true,
"test-speedcenter": true,
"quick": false,
},
{
"name": "Linux Debug",
"os": "ubuntu-latest",
"quick": false,
"CMAKE_OPTIONS": "-DCMAKE_BUILD_TYPE=Debug",
// exclude seriously slow tests
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest'"
},
{
"name": "Linux fsanitize",
"os": "ubuntu-latest",
"quick": false,
// turn off custom allocator & symbolic functions to make LSAN do its magic
"CMAKE_OPTIONS": "-DLEAN_EXTRA_CXX_FLAGS=-fsanitize=address,undefined -DLEANC_EXTRA_FLAGS='-fsanitize=address,undefined -fsanitize-link-c++-runtime' -DSMALL_ALLOCATOR=OFF -DBSYMBOLIC=OFF",
// exclude seriously slow/problematic tests (laketests crash)
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest'"
},
{
"name": "macOS",
"os": "macos-latest",
"release": true,
"quick": false,
"shell": "bash -euxo pipefail {0}",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-apple-darwin.tar.zst",
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm*",
"binary-check": "otool -L",
"tar": "gtar" // https://github.com/actions/runner-images/issues/2619
},
{
"name": "macOS aarch64",
"os": "macos-latest",
"release": true,
"quick": false,
"cross": true,
"cross_target": "aarch64-apple-darwin",
"shell": "bash -euxo pipefail {0}",
"CMAKE_OPTIONS": "-DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-darwin_aarch64",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-apple-darwin.tar.zst https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-apple-darwin.tar.zst",
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm-aarch64-* lean-llvm-x86_64-*",
"binary-check": "otool -L",
"tar": "gtar" // https://github.com/actions/runner-images/issues/2619
},
{
"name": "Windows",
"os": "windows-2022",
"release": true,
"quick": false,
"shell": "msys2 {0}",
"CMAKE_OPTIONS": "-G \"Unix Makefiles\" -DUSE_GMP=OFF",
// for reasons unknown, interactivetests are flaky on Windows
"CTEST_OPTIONS": "--repeat until-pass:2",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-w64-windows-gnu.tar.zst",
"prepare-llvm": "../script/prepare-llvm-mingw.sh lean-llvm*",
"binary-check": "ldd"
},
{
"name": "Linux aarch64",
"os": "ubuntu-latest",
"CMAKE_OPTIONS": "-DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-linux_aarch64",
"release": true,
"quick": false,
"cross": true,
"cross_target": "aarch64-unknown-linux-gnu",
"shell": "nix-shell --arg pkgsDist \"import (fetchTarball \\\"channel:nixos-19.03\\\") {{ localSystem.config = \\\"aarch64-unknown-linux-gnu\\\"; }}\" --run \"bash -euxo pipefail {0}\"",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-linux-gnu.tar.zst",
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm-aarch64-* lean-llvm-x86_64-*"
},
{
"name": "Linux 32bit",
"os": "ubuntu-latest",
// Use 32bit on stage0 and stage1 to keep oleans compatible
"CMAKE_OPTIONS": "-DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DLEAN_EXTRA_CXX_FLAGS='-m32' -DLEANC_OPTS='-m32' -DMMAP=OFF -DLEAN_INSTALL_SUFFIX=-linux_x86",
"cmultilib": true,
"release": true,
"quick": false,
"cross": true,
"shell": "bash -euxo pipefail {0}"
},
{
"name": "Web Assembly",
"os": "ubuntu-latest",
// Build a native 32bit binary in stage0 and use it to compile the oleans and the wasm build
"CMAKE_OPTIONS": "-DCMAKE_C_COMPILER_WORKS=1 -DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_CMAKE_CXX_COMPILER=clang++ -DSTAGE0_CMAKE_C_COMPILER=clang -DSTAGE0_CMAKE_EXECUTABLE_SUFFIX=\"\" -DUSE_GMP=OFF -DMMAP=OFF -DSTAGE0_MMAP=OFF -DCMAKE_AR=../emsdk/emsdk-main/upstream/emscripten/emar -DCMAKE_TOOLCHAIN_FILE=../emsdk/emsdk-main/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DLEAN_INSTALL_SUFFIX=-linux_wasm32",
"wasm": true,
"cmultilib": true,
"release": true,
"quick": false,
"cross": true,
"shell": "bash -euxo pipefail {0}",
// Just a few selected tests because wasm is slow
"CTEST_OPTIONS": "-R \"leantest_1007\\.lean|leantest_Format\\.lean|leanruntest\\_1037.lean|leanruntest_ac_rfl\\.lean\""
}
];
console.log(`matrix:\n${JSON.stringify(matrix, null, 2)}`)
if (quick) {
return matrix.filter((job) => job.quick)
} else {
return matrix
}
- name: Checkout
uses: actions/checkout@v3
# don't schedule nightlies on forks
@@ -240,6 +90,170 @@ jobs:
echo "Tag ${TAG_NAME} did not match SemVer regex."
fi
- name: Set check level
id: set-level
# We do not use github.event.pull_request.labels.*.name here because
# re-running a run does not update that list, and we do want to be able to
# rerun the workflow run after setting the `release-ci`/`merge-ci` labels.
run: |
check_level=0
if [[ -n "${{ steps.set-nightly.outputs.nightly }}" || -n "${{ steps.set-release.outputs.RELEASE_TAG }}" ]]; then
check_level=2
elif [[ "${{ github.event_name }}" != "pull_request" ]]; then
check_level=1
else
labels="$(gh api repos/${{ github.repository_owner }}/${{ github.event.repository.name }}/pulls/${{ github.event.pull_request.number }}) --jq '.labels'"
if echo "$labels" | grep -q "release-ci"; then
check_level=2
elif echo "$labels" | grep -q "merge-ci"; then
check_level=1
fi
fi
echo "check-level=$check_level" >> "$GITHUB_OUTPUT"
env:
GH_TOKEN: ${{ github.token }}
- name: Configure build matrix
id: set-matrix
uses: actions/github-script@v7
with:
script: |
const level = ${{ steps.set-level.outputs.check-level }};
console.log(`level: ${level}`);
// use large runners where available (original repo)
let large = ${{ github.repository == 'leanprover/lean4' }};
let matrix = [
{
// portable release build: use channel with older glibc (2.27)
"name": "Linux LLVM",
"os": "ubuntu-latest",
"release": false,
"check-level": 2,
"shell": "nix develop .#oldGlibc -c bash -euxo pipefail {0}",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst",
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*",
"binary-check": "ldd -v",
// foreign code may be linked against more recent glibc
// reverse-ffi needs to be updated to link to LLVM libraries
"CTEST_OPTIONS": "-E 'foreign|leanlaketest_reverse-ffi'",
"CMAKE_OPTIONS": "-DLLVM=ON -DLLVM_CONFIG=${GITHUB_WORKSPACE}/build/llvm-host/bin/llvm-config"
},
{
"name": "Linux release",
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
"release": true,
"check-level": 0,
"shell": "nix develop .#oldGlibc -c bash -euxo pipefail {0}",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst",
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm*",
"binary-check": "ldd -v",
// foreign code may be linked against more recent glibc
"CTEST_OPTIONS": "-E 'foreign'"
},
{
"name": "Linux",
"os": large ? "nscloud-ubuntu-22.04-amd64-4x8" : "ubuntu-latest",
"check-stage3": level >= 2,
"test-speedcenter": level >= 2,
"check-level": 1,
},
{
"name": "Linux Debug",
"os": "ubuntu-latest",
"check-level": 2,
"CMAKE_PRESET": "debug",
// exclude seriously slow tests
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest'"
},
// TODO: suddenly started failing in CI
/*{
"name": "Linux fsanitize",
"os": "ubuntu-latest",
"check-level": 2,
// turn off custom allocator & symbolic functions to make LSAN do its magic
"CMAKE_PRESET": "sanitize",
// exclude seriously slow/problematic tests (laketests crash)
"CTEST_OPTIONS": "-E 'interactivetest|leanpkgtest|laketest|benchtest'"
},*/
{
"name": "macOS",
"os": "macos-13",
"release": true,
"check-level": 2,
"shell": "bash -euxo pipefail {0}",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-apple-darwin.tar.zst",
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm*",
"binary-check": "otool -L",
"tar": "gtar" // https://github.com/actions/runner-images/issues/2619
},
{
"name": "macOS aarch64",
"os": "macos-14",
"CMAKE_OPTIONS": "-DLEAN_INSTALL_SUFFIX=-darwin_aarch64",
"release": true,
"check-level": 1,
"shell": "bash -euxo pipefail {0}",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-apple-darwin.tar.zst",
"prepare-llvm": "../script/prepare-llvm-macos.sh lean-llvm*",
"binary-check": "otool -L",
"tar": "gtar" // https://github.com/actions/runner-images/issues/2619
},
{
"name": "Windows",
"os": "windows-2022",
"release": true,
"check-level": 2,
"shell": "msys2 {0}",
"CMAKE_OPTIONS": "-G \"Unix Makefiles\" -DUSE_GMP=OFF",
// for reasons unknown, interactivetests are flaky on Windows
"CTEST_OPTIONS": "--repeat until-pass:2",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-w64-windows-gnu.tar.zst",
"prepare-llvm": "../script/prepare-llvm-mingw.sh lean-llvm*",
"binary-check": "ldd"
},
{
"name": "Linux aarch64",
"os": "ubuntu-latest",
"CMAKE_OPTIONS": "-DUSE_GMP=OFF -DLEAN_INSTALL_SUFFIX=-linux_aarch64",
"release": true,
"check-level": 2,
"cross": true,
"cross_target": "aarch64-unknown-linux-gnu",
"shell": "nix develop .#oldGlibcAArch -c bash -euxo pipefail {0}",
"llvm-url": "https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-x86_64-linux-gnu.tar.zst https://github.com/leanprover/lean-llvm/releases/download/15.0.1/lean-llvm-aarch64-linux-gnu.tar.zst",
"prepare-llvm": "../script/prepare-llvm-linux.sh lean-llvm-aarch64-* lean-llvm-x86_64-*"
},
{
"name": "Linux 32bit",
"os": "ubuntu-latest",
// Use 32bit on stage0 and stage1 to keep oleans compatible
"CMAKE_OPTIONS": "-DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_MMAP=OFF -DUSE_GMP=OFF -DLEAN_EXTRA_CXX_FLAGS='-m32' -DLEANC_OPTS='-m32' -DMMAP=OFF -DLEAN_INSTALL_SUFFIX=-linux_x86",
"cmultilib": true,
"release": true,
"check-level": 2,
"cross": true,
"shell": "bash -euxo pipefail {0}"
},
{
"name": "Web Assembly",
"os": "ubuntu-latest",
// Build a native 32bit binary in stage0 and use it to compile the oleans and the wasm build
"CMAKE_OPTIONS": "-DCMAKE_C_COMPILER_WORKS=1 -DSTAGE0_USE_GMP=OFF -DSTAGE0_LEAN_EXTRA_CXX_FLAGS='-m32' -DSTAGE0_LEANC_OPTS='-m32' -DSTAGE0_CMAKE_CXX_COMPILER=clang++ -DSTAGE0_CMAKE_C_COMPILER=clang -DSTAGE0_CMAKE_EXECUTABLE_SUFFIX=\"\" -DUSE_GMP=OFF -DMMAP=OFF -DSTAGE0_MMAP=OFF -DCMAKE_AR=../emsdk/emsdk-main/upstream/emscripten/emar -DCMAKE_TOOLCHAIN_FILE=../emsdk/emsdk-main/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake -DLEAN_INSTALL_SUFFIX=-linux_wasm32",
"wasm": true,
"cmultilib": true,
"release": true,
"check-level": 2,
"cross": true,
"shell": "bash -euxo pipefail {0}",
// Just a few selected tests because wasm is slow
"CTEST_OPTIONS": "-R \"leantest_1007\\.lean|leantest_Format\\.lean|leanruntest\\_1037.lean|leanruntest_ac_rfl\\.lean\""
}
];
console.log(`matrix:\n${JSON.stringify(matrix, null, 2)}`)
return matrix.filter((job) => level >= job["check-level"])
build:
needs: [configure]
if: github.event_name != 'schedule' || github.repository == 'leanprover/lean4'
@@ -251,7 +265,7 @@ jobs:
runs-on: ${{ matrix.os }}
defaults:
run:
shell: ${{ matrix.shell || 'nix-shell --run "bash -euxo pipefail {0}"' }}
shell: ${{ matrix.shell || 'nix develop -c bash -euxo pipefail {0}' }}
name: ${{ matrix.name }}
env:
# must be inside workspace
@@ -266,28 +280,34 @@ jobs:
CXX: c++
MACOSX_DEPLOYMENT_TARGET: 10.15
steps:
- name: Checkout
uses: actions/checkout@v3
with:
submodules: true
# the default is to use a virtual merge commit between the PR and master: just use the PR
ref: ${{ github.event.pull_request.head.sha }}
- name: Install Nix
uses: cachix/install-nix-action@v18
with:
install_url: https://releases.nixos.org/nix/nix-2.12.0/install
if: matrix.os == 'ubuntu-latest' && !matrix.cmultilib
uses: DeterminateSystems/nix-installer-action@main
if: runner.os == 'Linux' && !matrix.cmultilib
- name: Install MSYS2
uses: msys2/setup-msys2@v2
with:
msystem: clang64
# `:p` means prefix with appropriate msystem prefix
pacboy: "make python cmake:p clang:p ccache:p gmp:p git zip unzip diffutils binutils tree zstd:p tar"
if: matrix.os == 'windows-2022'
if: runner.os == 'Windows'
- name: Install Brew Packages
run: |
brew install ccache tree zstd coreutils gmp
if: matrix.os == 'macos-latest'
if: runner.os == 'macOS'
- name: Checkout
uses: actions/checkout@v4
with:
# the default is to use a virtual merge commit between the PR and master: just use the PR
ref: ${{ github.event.pull_request.head.sha }}
# Do check out some CI-relevant files from virtual merge commit to accommodate CI changes on
# master (as the workflow files themselves are always taken from the merge)
# (needs to be after "Install *" to use the right shell)
- name: CI Merge Checkout
run: |
git fetch --depth=1 origin ${{ github.sha }}
git checkout FETCH_HEAD flake.nix flake.lock
if: github.event_name == 'pull_request'
# (needs to be after "Checkout" so files don't get overriden)
- name: Setup emsdk
uses: mymindstorm/setup-emsdk@v12
with:
@@ -303,26 +323,22 @@ jobs:
uses: actions/cache@v3
with:
path: .ccache
key: ${{ matrix.name }}-build-v3-${{ github.sha }}
key: ${{ matrix.name }}-build-v3-${{ github.event.pull_request.head.sha }}
# fall back to (latest) previous cache
restore-keys: |
${{ matrix.name }}-build-v3
# open nix-shell once for initial setup
- name: Setup
run: |
# open nix-shell once for initial setup
true
if: matrix.os == 'ubuntu-latest'
- name: Set up core dumps
ccache --zero-stats
if: runner.os == 'Linux'
- name: Set up NPROC
run: |
mkdir -p $PWD/coredumps
# store in current directory, for easy uploading together with binary
echo $PWD/coredumps/%e.%p.%t | sudo tee /proc/sys/kernel/core_pattern
if: matrix.os == 'ubuntu-latest'
echo "NPROC=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4)" >> $GITHUB_ENV
- name: Build
run: |
mkdir build
cd build
ulimit -c unlimited # coredumps
# arguments passed to `cmake`
# this also enables githash embedding into stage 1 library
OPTIONS=(-DCHECK_OLEAN_VERSION=ON)
@@ -348,9 +364,11 @@ jobs:
OPTIONS+=(-DLEAN_SPECIAL_VERSION_DESC=${{ needs.configure.outputs.LEAN_SPECIAL_VERSION_DESC }})
fi
# contortion to support empty OPTIONS with old macOS bash
cmake .. ${{ matrix.CMAKE_OPTIONS }} ${OPTIONS[@]+"${OPTIONS[@]}"} -DLEAN_INSTALL_PREFIX=$PWD/..
make -j4
make install
cmake .. --preset ${{ matrix.CMAKE_PRESET || 'release' }} -B . ${{ matrix.CMAKE_OPTIONS }} ${OPTIONS[@]+"${OPTIONS[@]}"} -DLEAN_INSTALL_PREFIX=$PWD/..
time make -j$NPROC
- name: Install
run: |
make -C build install
- name: Check Binaries
run: ${{ matrix.binary-check }} lean-*/bin/* || true
- name: List Install Tree
@@ -378,62 +396,43 @@ jobs:
build/stage1/bin/lean --stats src/Lean.lean
if: ${{ !matrix.cross }}
- name: Test
id: test
run: |
cd build/stage1
ulimit -c unlimited # coredumps
# exclude nonreproducible test
ctest -j4 --output-on-failure ${{ matrix.CTEST_OPTIONS }} < /dev/null
if: (matrix.wasm || !matrix.cross) && needs.configure.outputs.quick == 'false'
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/stage1 -j$NPROC --output-junit test-results.xml ${{ matrix.CTEST_OPTIONS }}
if: (matrix.wasm || !matrix.cross) && needs.configure.outputs.check-level >= 1
- name: Test Summary
uses: test-summary/action@v2
with:
paths: build/stage1/test-results.xml
# prefix `if` above with `always` so it's run even if tests failed
if: always() && steps.test.conclusion != 'skipped'
- name: Check Test Binary
run: ${{ matrix.binary-check }} tests/compiler/534.lean.out
if: ${{ !matrix.cross && needs.configure.outputs.quick == 'false' }}
if: (!matrix.cross) && steps.test.conclusion != 'skipped'
- name: Build Stage 2
run: |
cd build
ulimit -c unlimited # coredumps
make -j4 stage2
make -C build -j$NPROC stage2
if: matrix.test-speedcenter
- name: Check Stage 3
run: |
cd build
ulimit -c unlimited # coredumps
make -j4 check-stage3
make -C build -j$NPROC stage3
if: matrix.test-speedcenter
- name: Test Speedcenter Benchmarks
run: |
echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
# Necessary for some timing metrics but does not work on Namespace runners
# and we just want to test that the benchmarks run at all here
#echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid
export BUILD=$PWD/build PATH=$PWD/build/stage1/bin:$PATH
cd tests/bench
nix shell .#temci -c temci exec --config speedcenter.yaml --included_blocks fast --runs 1
if: matrix.test-speedcenter
- name: Check rebootstrap
run: |
cd build
ulimit -c unlimited # coredumps
make update-stage0 && make -j4
if: matrix.name == 'Linux' && needs.configure.outputs.quick == 'false'
# clean rebuild in case of Makefile changes
make -C build update-stage0 && rm -rf build/stage* && make -C build -j$NPROC
if: matrix.name == 'Linux' && needs.configure.outputs.check-level >= 1
- name: CCache stats
run: ccache -s
- name: Show stacktrace for coredumps
if: ${{ failure() && matrix.os == 'ubuntu-latest' }}
run: |
for c in coredumps/*; do
progbin="$(file $c | sed "s/.*execfn: '\([^']*\)'.*/\1/")"
echo bt | $GDB/bin/gdb -q $progbin $c || true
done
- name: Upload coredumps
uses: actions/upload-artifact@v3
if: ${{ failure() && matrix.os == 'ubuntu-latest' }}
with:
name: coredumps-${{ matrix.name }}
path: |
./coredumps
./build/stage0/bin/lean
./build/stage0/lib/lean/libleanshared.so
./build/stage1/bin/lean
./build/stage1/lib/lean/libleanshared.so
./build/stage2/bin/lean
./build/stage2/lib/lean/libleanshared.so
# This job collects results from all the matrix jobs
# This can be made the “required” job, instead of listing each
@@ -442,9 +441,10 @@ jobs:
name: Build matrix complete
runs-on: ubuntu-latest
needs: build
if: ${{ always() }}
# mark as merely cancelled not failed if builds are cancelled
if: ${{ !cancelled() }}
steps:
- if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
- if: contains(needs.*.result, 'failure')
uses: actions/github-script@v7
with:
script: |
@@ -467,6 +467,7 @@ jobs:
with:
files: artifacts/*/*
fail_on_unmatched_files: true
prerelease: ${{ !startsWith(github.ref, 'refs/tags/v') || contains(github.ref, '-rc') }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

20
.github/workflows/copyright-header.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Check for copyright header
on: [pull_request]
jobs:
check-lean-files:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify .lean files start with a copyright header.
run: |
FILES=$(find ./src -type d \( -path "./src/lake/examples" -o -path "./src/lake/tests" \) -prune -o -type f -name "*.lean" -exec perl -ne 'BEGIN { $/ = undef; } print "$ARGV\n" if !m{\A/-\nCopyright}; exit;' {} \;)
if [ -n "$FILES" ]; then
echo "Found .lean files which do not have a copyright header:"
echo "$FILES"
exit 1
else
echo "All copyright headers present."
fi

View File

@@ -13,18 +13,36 @@ concurrency:
cancel-in-progress: true
jobs:
# see ci.yml
configure:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.result }}
steps:
- name: Configure build matrix
id: set-matrix
uses: actions/github-script@v7
with:
script: |
let large = ${{ github.repository == 'leanprover/lean4' }};
let matrix = [
{
"name": "Nix Linux",
"os": large ? "nscloud-ubuntu-22.04-amd64-8x8" : "ubuntu-latest",
}
];
console.log(`matrix:\n${JSON.stringify(matrix, null, 2)}`);
return matrix;
Build:
needs: [configure]
runs-on: ${{ matrix.os }}
defaults:
run:
shell: nix run .#ciShell -- bash -euxo pipefail {0}
strategy:
matrix:
include:
- name: Nix Linux
os: ubuntu-latest
#- name: Nix macOS
# os: macos-latest
include: ${{fromJson(needs.configure.outputs.matrix)}}
# complete all jobs
fail-fast: false
name: ${{ matrix.name }}
@@ -71,18 +89,18 @@ jobs:
run: |
sudo chown -R root:nixbld /nix/var/cache
sudo chmod -R 770 /nix/var/cache
- name: Install Cachix
uses: cachix/cachix-action@v12
with:
name: lean4
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
skipPush: true # we push specific outputs only
- name: Build
run: |
nix build $NIX_BUILD_ARGS .#cacheRoots -o push-build
- name: Test
run: |
nix build $NIX_BUILD_ARGS .#test -o push-test
nix build --keep-failed $NIX_BUILD_ARGS .#test -o push-test || (ln -s /tmp/nix-build-*/source/src/build/ ./push-test; false)
- name: Test Summary
uses: test-summary/action@v2
with:
paths: push-test/test-results.xml
if: always()
continue-on-error: true
- name: Build manual
run: |
nix build $NIX_BUILD_ARGS --update-input lean --no-write-lock-file ./doc#{lean-mdbook,leanInk,alectryon,test,inked} -o push-doc
@@ -98,9 +116,6 @@ jobs:
# gmplib.org consistently times out from GH actions
# the GitHub token is to avoid rate limiting
args: --base './dist' --no-progress --github-token ${{ secrets.GITHUB_TOKEN }} --exclude 'gmplib.org' './dist/**/*.html'
- name: Push to Cachix
run: |
[ -z "${{ secrets.CACHIX_AUTH_TOKEN }}" ] || cachix push -j4 lean4 ./push-* || true
- name: Rebuild Nix Store Cache
run: |
rm -rf nix-store-cache || true

View File

@@ -126,24 +126,22 @@ jobs:
if [ "$NIGHTLY_SHA" = "$MERGE_BASE_SHA" ]; then
echo "The merge base of this PR coincides with the nightly release"
BATTERIES_REMOTE_TAGS="$(git ls-remote https://github.com/leanprover-community/batteries.git nightly-testing-"$MOST_RECENT_NIGHTLY")"
MATHLIB_REMOTE_TAGS="$(git ls-remote https://github.com/leanprover-community/mathlib4.git nightly-testing-"$MOST_RECENT_NIGHTLY")"
if [[ -n "$MATHLIB_REMOTE_TAGS" ]]; then
echo "... and Mathlib has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
if [[ -n "$BATTERIES_REMOTE_TAGS" ]]; then
echo "... and Batteries has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
MESSAGE=""
else
echo "... but Mathlib does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
MESSAGE="- ❗ Mathlib CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Mathlib CI should run now."
fi
STD_REMOTE_TAGS="$(git ls-remote https://github.com/leanprover/std4.git nightly-testing-"$MOST_RECENT_NIGHTLY")"
if [[ -n "$STD_REMOTE_TAGS" ]]; then
echo "... and Std has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
MESSAGE=""
if [[ -n "$MATHLIB_REMOTE_TAGS" ]]; then
echo "... and Mathlib has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
else
echo "... but Mathlib does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
MESSAGE="- ❗ Mathlib CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Mathlib CI should run now."
fi
else
echo "... but Std does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
MESSAGE="- ❗ Std CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Std CI should run now."
echo "... but Batteries does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
MESSAGE="- ❗ Batteries CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Batteries CI should run now."
fi
else
@@ -151,7 +149,9 @@ jobs:
echo "but 'git merge-base origin/master HEAD' reported: $MERGE_BASE_SHA"
git -C lean4.git log -10 origin/master
MESSAGE="- ❗ Std/Mathlib CI will not be attempted unless your PR branches off the \`nightly-with-mathlib\` branch."
git -C lean4.git fetch origin nightly-with-mathlib
NIGHTLY_WITH_MATHLIB_SHA="$(git -C lean4.git rev-parse "origin/nightly-with-mathlib")"
MESSAGE="- ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the \`nightly-with-mathlib\` branch. Try \`git rebase $MERGE_BASE_SHA --onto $NIGHTLY_WITH_MATHLIB_SHA\`."
fi
if [[ -n "$MESSAGE" ]]; then
@@ -223,27 +223,27 @@ jobs:
description: description,
});
# We next automatically create a Std branch using this toolchain.
# Std doesn't itself have a mechanism to report results of CI from this branch back to Lean
# Instead this is taken care of by Mathlib CI, which will fail if Std fails.
# We next automatically create a Batteries branch using this toolchain.
# Batteries doesn't itself have a mechanism to report results of CI from this branch back to Lean
# Instead this is taken care of by Mathlib CI, which will fail if Batteries fails.
- name: Cleanup workspace
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
run: |
sudo rm -rf ./*
# Checkout the Std repository with all branches
- name: Checkout Std repository
# Checkout the Batteries repository with all branches
- name: Checkout Batteries repository
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
uses: actions/checkout@v3
with:
repository: leanprover/std4
repository: leanprover-community/batteries
token: ${{ secrets.MATHLIB4_BOT }}
ref: nightly-testing
fetch-depth: 0 # This ensures we check out all tags and branches.
- name: Check if tag exists
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
id: check_std_tag
id: check_batteries_tag
run: |
git config user.name "leanprover-community-mathlib4-bot"
git config user.email "leanprover-community-mathlib4-bot@users.noreply.github.com"
@@ -251,7 +251,7 @@ jobs:
if git ls-remote --heads --tags --exit-code origin "nightly-testing-${MOST_RECENT_NIGHTLY}" >/dev/null; then
BASE="nightly-testing-${MOST_RECENT_NIGHTLY}"
else
echo "This shouldn't be possible: couldn't find a 'nightly-testing-${MOST_RECENT_NIGHTLY}' tag at Std. Falling back to 'nightly-testing'."
echo "This shouldn't be possible: couldn't find a 'nightly-testing-${MOST_RECENT_NIGHTLY}' tag at Batteries. Falling back to 'nightly-testing'."
BASE=nightly-testing
fi
@@ -268,7 +268,7 @@ jobs:
else
echo "Branch already exists, pushing an empty commit."
git switch lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
# The Std `nightly-testing` or `nightly-testing-YYYY-MM-DD` branch may have moved since this branch was created, so merge their changes.
# The Batteries `nightly-testing` or `nightly-testing-YYYY-MM-DD` branch may have moved since this branch was created, so merge their changes.
# (This should no longer be possible once `nightly-testing-YYYY-MM-DD` is a tag, but it is still safe to merge.)
git merge "$BASE" --strategy-option ours --no-commit --allow-unrelated-histories
git commit --allow-empty -m "Trigger CI for https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
@@ -298,6 +298,13 @@ jobs:
ref: nightly-testing
fetch-depth: 0 # This ensures we check out all tags and branches.
- name: install elan
run: |
set -o pipefail
curl -sSfL https://github.com/leanprover/elan/releases/download/v3.0.0/elan-x86_64-unknown-linux-gnu.tar.gz | tar xz
./elan-init -y --default-toolchain none
echo "$HOME/.elan/bin" >> "${GITHUB_PATH}"
- name: Check if tag exists
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
id: check_mathlib_tag
@@ -321,8 +328,9 @@ jobs:
git switch -c lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }} "$BASE"
echo "leanprover/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}" > lean-toolchain
git add lean-toolchain
sed -i "s/require std from git \"https:\/\/github.com\/leanprover\/std4\" @ \".\+\"/require std from git \"https:\/\/github.com\/leanprover\/std4\" @ \"nightly-testing-${MOST_RECENT_NIGHTLY}\"/" lakefile.lean
git add lakefile.lean
sed -i "s/require batteries from git \"https:\/\/github.com\/leanprover-community\/batteries\" @ \".\+\"/require batteries from git \"https:\/\/github.com\/leanprover-community\/batteries\" @ \"nightly-testing-${MOST_RECENT_NIGHTLY}\"/" lakefile.lean
lake update batteries
git add lakefile.lean lake-manifest.json
git commit -m "Update lean-toolchain for testing https://github.com/leanprover/lean4/pull/${{ steps.workflow-info.outputs.pullRequestNumber }}"
else
echo "Branch already exists, pushing an empty commit."

31
.github/workflows/restart-on-label.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Restart by label
on:
pull_request_target:
types:
- unlabeled
- labeled
jobs:
restart-on-label:
runs-on: ubuntu-latest
if: contains(github.event.label.name, 'merge-ci') || contains(github.event.label.name, 'release-ci')
steps:
- run: |
# Finding latest CI workflow run on current pull request
# (unfortunately cannot search by PR number, only base branch,
# and that is't even unique given PRs from forks, but the risk
# of confusion is low and the danger is mild)
run_id=$(gh run list -e pull_request -b "$head_ref" --workflow 'CI' --limit 1 \
--limit 1 --json databaseId --jq '.[0].databaseId')
echo "Run id: ${run_id}"
gh run view "$run_id"
echo "Cancelling (just in case)"
gh run cancel "$run_id" || echo "(failed)"
echo "Waiting for 10s"
sleep 10
echo "Rerunning"
gh run rerun "$run_id"
shell: bash
env:
head_ref: ${{ github.head_ref }}
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}

View File

@@ -40,18 +40,32 @@ jobs:
run: |
git config --global user.name "Lean stage0 autoupdater"
git config --global user.email "<>"
- if: env.should_update_stage0 == 'yes'
uses: DeterminateSystems/nix-installer-action@main
# Would be nice, but does not work yet:
# https://github.com/DeterminateSystems/magic-nix-cache/issues/39
# This action does not run that often and building runs in a few minutes, so ok for now
#- if: env.should_update_stage0 == 'yes'
# uses: DeterminateSystems/magic-nix-cache-action@v2
- if: env.should_update_stage0 == 'yes'
name: Install Cachix
uses: cachix/cachix-action@v12
name: Restore Build Cache
uses: actions/cache/restore@v3
with:
name: lean4
path: nix-store-cache
key: Nix Linux-nix-store-cache-${{ github.sha }}
# fall back to (latest) previous cache
restore-keys: |
Nix Linux-nix-store-cache
- if: env.should_update_stage0 == 'yes'
name: Further Set Up Nix Cache
shell: bash -euxo pipefail {0}
run: |
# Nix seems to mutate the cache, so make a copy
cp -r nix-store-cache nix-store-cache-copy || true
- if: env.should_update_stage0 == 'yes'
name: Install Nix
uses: DeterminateSystems/nix-installer-action@main
with:
extra-conf: |
substituters = file://${{ github.workspace }}/nix-store-cache-copy?priority=10&trusted=true https://cache.nixos.org
- if: env.should_update_stage0 == 'yes'
run: nix run .#update-stage0-commit
- if: env.should_update_stage0 == 'yes'

6
.gitignore vendored
View File

@@ -4,8 +4,10 @@
*.lock
.lake
lake-manifest.json
build
!/src/lake/Lake/Build
/build
/src/lakefile.toml
/tests/lakefile.toml
/lakefile.toml
GPATH
GRTAGS
GSYMS

View File

@@ -78,6 +78,10 @@ add_custom_target(update-stage0
COMMAND $(MAKE) -C stage1 update-stage0
DEPENDS stage1)
add_custom_target(update-stage0-commit
COMMAND $(MAKE) -C stage1 update-stage0-commit
DEPENDS stage1)
add_custom_target(test
COMMAND $(MAKE) -C stage1 test
DEPENDS stage1)

83
CMakePresets.json Normal file
View File

@@ -0,0 +1,83 @@
{
"version": 2,
"cmakeMinimumRequired": {
"major": 3,
"minor": 10,
"patch": 0
},
"configurePresets": [
{
"name": "release",
"displayName": "Default development optimized build config",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build/release"
},
{
"name": "debug",
"displayName": "Debug build config",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug"
},
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build/debug"
},
{
"name": "sanitize",
"displayName": "Sanitize build config",
"cacheVariables": {
"LEAN_EXTRA_CXX_FLAGS": "-fsanitize=address,undefined",
"LEANC_EXTRA_FLAGS": "-fsanitize=address,undefined -fsanitize-link-c++-runtime",
"SMALL_ALLOCATOR": "OFF",
"BSYMBOLIC": "OFF"
},
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build/sanitize"
},
{
"name": "sandebug",
"inherits": ["debug", "sanitize"],
"displayName": "Sanitize+debug build config",
"binaryDir": "${sourceDir}/build/sandebug"
}
],
"buildPresets": [
{
"name": "release",
"configurePreset": "release"
},
{
"name": "debug",
"configurePreset": "debug"
},
{
"name": "sanitize",
"configurePreset": "sanitize"
},
{
"name": "sandebug",
"configurePreset": "sandebug"
}
],
"testPresets": [
{
"name": "release",
"configurePreset": "release",
"output": {"outputOnFailure": true, "shortProgress": true}
},
{
"name": "debug",
"configurePreset": "debug",
"inherits": "release"
},
{
"name": "sanitize",
"configurePreset": "sanitize",
"inherits": "release"
},
{
"name": "sandebug",
"configurePreset": "sandebug",
"inherits": "release"
}
]
}

View File

@@ -6,17 +6,40 @@
/.github/ @Kha @semorrison
/RELEASES.md @semorrison
/src/ @leodemoura @Kha
/src/Init/IO.lean @joehendrix
/src/kernel/ @leodemoura
/src/lake/ @tydeu
/src/Lean/Compiler/ @leodemoura
/src/Lean/Data/Lsp/ @mhuisi
/src/Lean/Elab/Deriving/ @semorrison
/src/Lean/Elab/Tactic/ @semorrison
/src/Lean/Language/ @Kha
/src/Lean/Meta/Tactic/ @leodemoura
/src/Lean/Parser/ @Kha
/src/Lean/PrettyPrinter/ @Kha
/src/Lean/PrettyPrinter/Delaborator/ @kmill
/src/Lean/Server/ @mhuisi
/src/Lean/Widget/ @Vtec234
/src/runtime/io.cpp @joehendrix
/src/Init/Data/ @semorrison
/src/Init/Data/Array/Lemmas.lean @digama0
/src/Init/Data/List/Lemmas.lean @digama0
/src/Init/Data/List/BasicAux.lean @digama0
/src/Init/Data/Array/Subarray.lean @david-christiansen
/src/Lean/Elab/Tactic/RCases.lean @digama0
/src/Init/RCases.lean @digama0
/src/Lean/Elab/Tactic/Ext.lean @digama0
/src/Init/Ext.lean @digama0
/src/Lean/Elab/Tactic/Simpa.lean @digama0
/src/Lean/Elab/Tactic/NormCast.lean @digama0
/src/Lean/Meta/Tactic/NormCast.lean @digama0
/src/Lean/Meta/Tactic/TryThis.lean @digama0
/src/Lean/Elab/Tactic/SimpTrace.lean @digama0
/src/Lean/Elab/Tactic/NoMatch.lean @digama0
/src/Lean/Elab/Tactic/ShowTerm.lean @digama0
/src/Lean/Elab/Tactic/Repeat.lean @digama0
/src/Lean/Meta/Tactic/Repeat.lean @digama0
/src/Lean/Meta/CoeAttr.lean @digama0
/src/Lean/Elab/GuardMsgs.lean @digama0
/src/Lean/Elab/Tactic/Guard.lean @digama0
/src/Init/Guard.lean @digama0
/src/Lean/Server/CodeActions/ @digama0

View File

@@ -22,4 +22,4 @@ Please read our [Contribution Guidelines](CONTRIBUTING.md) first.
# Building from Source
See [Building Lean](https://lean-lang.org/lean4/doc/make/index.html).
See [Building Lean](https://lean-lang.org/lean4/doc/make/index.html) (documentation source: [doc/make/index.md](doc/make/index.md)).

View File

@@ -8,74 +8,766 @@ This file contains work-in-progress notes for the upcoming release, as well as p
Please check the [releases](https://github.com/leanprover/lean4/releases) page for the current status
of each version.
v4.7.0 (development in progress)
v4.10.0
----------
Development in progress.
v4.9.0
----------
Release candidate, release notes will be copied from branch `releases/v4.9.0` once completed.
v4.8.0
---------
### Language features, tactics, and metaprograms
* **Functional induction principles.**
[#3432](https://github.com/leanprover/lean4/pull/3432), [#3620](https://github.com/leanprover/lean4/pull/3620),
[#3754](https://github.com/leanprover/lean4/pull/3754), [#3762](https://github.com/leanprover/lean4/pull/3762),
[#3738](https://github.com/leanprover/lean4/pull/3738), [#3776](https://github.com/leanprover/lean4/pull/3776),
[#3898](https://github.com/leanprover/lean4/pull/3898).
Derived from the definition of a (possibly mutually) recursive function,
a **functional induction principle** is created that is tailored to proofs about that function.
For example from:
```
def ackermann : Nat → Nat → Nat
| 0, m => m + 1
| n+1, 0 => ackermann n 1
| n+1, m+1 => ackermann n (ackermann (n + 1) m)
```
we get
```
ackermann.induct (motive : Nat → Nat → Prop) (case1 : ∀ (m : Nat), motive 0 m)
(case2 : ∀ (n : Nat), motive n 1 → motive (Nat.succ n) 0)
(case3 : ∀ (n m : Nat), motive (n + 1) m → motive n (ackermann (n + 1) m) → motive (Nat.succ n) (Nat.succ m))
(x x : Nat) : motive x x
```
It can be used in the `induction` tactic using the `using` syntax:
```
induction n, m using ackermann.induct
```
* The termination checker now recognizes more recursion patterns without an
explicit `termination_by`. In particular the idiom of counting up to an upper
bound, as in
```
def Array.sum (arr : Array Nat) (i acc : Nat) : Nat :=
if _ : i < arr.size then
Array.sum arr (i+1) (acc + arr[i])
else
acc
```
is recognized without having to say `termination_by arr.size - i`.
* [#3630](https://github.com/leanprover/lean4/pull/3630) makes `termination_by?` not use `sizeOf` when not needed
* [#3652](https://github.com/leanprover/lean4/pull/3652) improves the `termination_by` syntax.
* [#3658](https://github.com/leanprover/lean4/pull/3658) changes how termination arguments are elaborated.
* [#3665](https://github.com/leanprover/lean4/pull/3665) refactors GuessLex to allow inferring more complex termination arguments
* [#3666](https://github.com/leanprover/lean4/pull/3666) infers termination arguments such as `xs.size - i`
* [#3629](https://github.com/leanprover/lean4/pull/3629),
[#3655](https://github.com/leanprover/lean4/pull/3655),
[#3747](https://github.com/leanprover/lean4/pull/3747):
Adds `@[induction_eliminator]` and `@[cases_eliminator]` attributes to be able to define custom eliminators
for the `induction` and `cases` tactics, replacing the `@[eliminator]` attribute.
Gives custom eliminators for `Nat` so that `induction` and `cases` put goal states into terms of `0` and `n + 1`
rather than `Nat.zero` and `Nat.succ n`.
Added option `tactic.customEliminators` to control whether to use custom eliminators.
Added a hack for `rcases`/`rintro`/`obtain` to use the custom eliminator for `Nat`.
* **Shorter instances names.** There is a new algorithm for generating names for anonymous instances.
Across Std and Mathlib, the median ratio between lengths of new names and of old names is about 72%.
With the old algorithm, the longest name was 1660 characters, and now the longest name is 202 characters.
The new algorithm's 95th percentile name length is 67 characters, versus 278 for the old algorithm.
While the new algorithm produces names that are 1.2% less unique,
it avoids cross-project collisions by adding a module-based suffix
when it does not refer to declarations from the same "project" (modules that share the same root).
[#3089](https://github.com/leanprover/lean4/pull/3089)
and [#3934](https://github.com/leanprover/lean4/pull/3934).
* [8d2adf](https://github.com/leanprover/lean4/commit/8d2adf521d2b7636347a5b01bfe473bf0fcfaf31)
Importing two different files containing proofs of the same theorem is no longer considered an error.
This feature is particularly useful for theorems that are automatically generated on demand (e.g., equational theorems).
* [84b091](https://github.com/leanprover/lean4/commit/84b0919a116e9be12f933e764474f45d964ce85c)
Lean now generates an error if the type of a theorem is **not** a proposition.
* **Definition transparency.** [47a343](https://github.com/leanprover/lean4/commit/47a34316fc03ce936fddd2d3dce44784c5bcdfa9). `@[reducible]`, `@[semireducible]`, and `@[irreducible]` are now scoped and able to be set for imported declarations.
* `simp`/`dsimp`
* [#3607](https://github.com/leanprover/lean4/pull/3607) enables kernel projection reduction in `dsimp`
* [b24fbf](https://github.com/leanprover/lean4/commit/b24fbf44f3aaa112f5d799ef2a341772d1eb222d)
and [acdb00](https://github.com/leanprover/lean4/commit/acdb0054d5a0efa724cff596ac26852fad5724c4):
`dsimproc` command
to define defeq-preserving simplification procedures.
* [#3624](https://github.com/leanprover/lean4/pull/3624) makes `dsimp` normalize raw nat literals as `OfNat.ofNat` applications.
* [#3628](https://github.com/leanprover/lean4/pull/3628) makes `simp` correctly handle `OfScientific.ofScientific` literals.
* [#3654](https://github.com/leanprover/lean4/pull/3654) makes `dsimp?` report used simprocs.
* [dee074](https://github.com/leanprover/lean4/commit/dee074dcde03a37b7895a4901df2e4fa490c73c7) fixes equation theorem
handling in `simp` for non-recursive definitions.
* [#3819](https://github.com/leanprover/lean4/pull/3819) improved performance when simp encounters a loop.
* [#3821](https://github.com/leanprover/lean4/pull/3821) fixes discharger/cache interaction.
* [#3824](https://github.com/leanprover/lean4/pull/3824) keeps `simp` from breaking `Char` literals.
* [#3838](https://github.com/leanprover/lean4/pull/3838) allows `Nat` instances matching to be more lenient.
* [#3870](https://github.com/leanprover/lean4/pull/3870) documentation for `simp` configuration options.
* [#3972](https://github.com/leanprover/lean4/pull/3972) fixes simp caching.
* [#4044](https://github.com/leanprover/lean4/pull/4044) improves cache behavior for "well-behaved" dischargers.
* `omega`
* [#3639](https://github.com/leanprover/lean4/pull/3639), [#3766](https://github.com/leanprover/lean4/pull/3766),
[#3853](https://github.com/leanprover/lean4/pull/3853), [#3875](https://github.com/leanprover/lean4/pull/3875):
introduces a term canonicalizer.
* [#3736](https://github.com/leanprover/lean4/pull/3736) improves handling of positivity for the modulo operator for `Int`.
* [#3828](https://github.com/leanprover/lean4/pull/3828) makes it work as a `simp` discharger.
* [#3847](https://github.com/leanprover/lean4/pull/3847) adds helpful error messages.
* `rfl`
* [#3671](https://github.com/leanprover/lean4/pull/3671), [#3708](https://github.com/leanprover/lean4/pull/3708): upstreams the `@[refl]` attribute and the `rfl` tactic.
* [#3751](https://github.com/leanprover/lean4/pull/3751) makes `apply_rfl` not operate on `Eq` itself.
* [#4067](https://github.com/leanprover/lean4/pull/4067) improves error message when there are no goals.
* [#3719](https://github.com/leanprover/lean4/pull/3719) upstreams the `rw?` tactic, with fixes and improvements in
[#3783](https://github.com/leanprover/lean4/pull/3783), [#3794](https://github.com/leanprover/lean4/pull/3794),
[#3911](https://github.com/leanprover/lean4/pull/3911).
* `conv`
* [#3659](https://github.com/leanprover/lean4/pull/3659) adds a `conv` version of the `calc` tactic.
* [#3763](https://github.com/leanprover/lean4/pull/3763) makes `conv` clean up using `try with_reducible rfl` instead of `try rfl`.
* `#guard_msgs`
* [#3617](https://github.com/leanprover/lean4/pull/3617) introduces whitespace protection using the `` character.
* [#3883](https://github.com/leanprover/lean4/pull/3883):
The `#guard_msgs` command now has options to change whitespace normalization and sensitivity to message ordering.
For example, `#guard_msgs (whitespace := lax) in cmd` collapses whitespace before checking messages,
and `#guard_msgs (ordering := sorted) in cmd` sorts the messages in lexicographic order before checking.
* [#3931](https://github.com/leanprover/lean4/pull/3931) adds an unused variables ignore function for `#guard_msgs`.
* [#3912](https://github.com/leanprover/lean4/pull/3912) adds a diff between the expected and actual outputs. This feature is currently
disabled by default, but can be enabled with `set_option guard_msgs.diff true`.
Depending on user feedback, this option may default to `true` in a future version of Lean.
* `do` **notation**
* [#3820](https://github.com/leanprover/lean4/pull/3820) makes it an error to lift `(<- ...)` out of a pure `if ... then ... else ...`
* **Lazy discrimination trees**
* [#3610](https://github.com/leanprover/lean4/pull/3610) fixes a name collision for `LazyDiscrTree` that could lead to cache poisoning.
* [#3677](https://github.com/leanprover/lean4/pull/3677) simplifies and fixes `LazyDiscrTree` handling for `exact?`/`apply?`.
* [#3685](https://github.com/leanprover/lean4/pull/3685) moves general `exact?`/`apply?` functionality into `LazyDiscrTree`.
* [#3769](https://github.com/leanprover/lean4/pull/3769) has lemma selection improvements for `rw?` and `LazyDiscrTree`.
* [#3818](https://github.com/leanprover/lean4/pull/3818) improves ordering of matches.
* [#3590](https://github.com/leanprover/lean4/pull/3590) adds `inductive.autoPromoteIndices` option to be able to disable auto promotion of indices in the `inductive` command.
* **Miscellaneous bug fixes and improvements**
* [#3606](https://github.com/leanprover/lean4/pull/3606) preserves `cache` and `dischargeDepth` fields in `Lean.Meta.Simp.Result.mkEqSymm`.
* [#3633](https://github.com/leanprover/lean4/pull/3633) makes `elabTermEnsuringType` respect `errToSorry`, improving error recovery of the `have` tactic.
* [#3647](https://github.com/leanprover/lean4/pull/3647) enables `noncomputable unsafe` definitions, for deferring implementations until later.
* [#3672](https://github.com/leanprover/lean4/pull/3672) adjust namespaces of tactics.
* [#3725](https://github.com/leanprover/lean4/pull/3725) fixes `Ord` derive handler for indexed inductive types with unused alternatives.
* [#3893](https://github.com/leanprover/lean4/pull/3893) improves performance of derived `Ord` instances.
* [#3771](https://github.com/leanprover/lean4/pull/3771) changes error reporting for failing tactic macros. Improves `rfl` error message.
* [#3745](https://github.com/leanprover/lean4/pull/3745) fixes elaboration of generalized field notation if the object of the notation is an optional parameter.
* [#3799](https://github.com/leanprover/lean4/pull/3799) makes commands such as `universe`, `variable`, `namespace`, etc. require that their argument appear in a later column.
Commands that can optionally parse an `ident` or parse any number of `ident`s generally should require
that the `ident` use `colGt`. This keeps typos in commands from being interpreted as identifiers.
* [#3815](https://github.com/leanprover/lean4/pull/3815) lets the `split` tactic be used for writing code.
* [#3822](https://github.com/leanprover/lean4/pull/3822) adds missing info in `induction` tactic for `with` clauses of the form `| cstr a b c => ?_`.
* [#3806](https://github.com/leanprover/lean4/pull/3806) fixes `withSetOptionIn` combinator.
* [#3844](https://github.com/leanprover/lean4/pull/3844) removes unused `trace.Elab.syntax` option.
* [#3896](https://github.com/leanprover/lean4/pull/3896) improves hover and go-to-def for `attribute` command.
* [#3989](https://github.com/leanprover/lean4/pull/3989) makes linter options more discoverable.
* [#3916](https://github.com/leanprover/lean4/pull/3916) fixes go-to-def for syntax defined with `@[builtin_term_parser]`.
* [#3962](https://github.com/leanprover/lean4/pull/3962) fixes how `solveByElim` handles `symm` lemmas, making `exact?`/`apply?` usable again.
* [#3968](https://github.com/leanprover/lean4/pull/3968) improves the `@[deprecated]` attribute, adding `(since := "<date>")` field.
* [#3768](https://github.com/leanprover/lean4/pull/3768) makes `#print` command show structure fields.
* [#3974](https://github.com/leanprover/lean4/pull/3974) makes `exact?%` behave like `by exact?` rather than `by apply?`.
* [#3994](https://github.com/leanprover/lean4/pull/3994) makes elaboration of `he ▸ h` notation more predictable.
* [#3991](https://github.com/leanprover/lean4/pull/3991) adjusts transparency for `decreasing_trivial` macros.
* [#4092](https://github.com/leanprover/lean4/pull/4092) improves performance of `binop%` and `binrel%` expression tree elaborators.
* **Docs:** [#3748](https://github.com/leanprover/lean4/pull/3748), [#3796](https://github.com/leanprover/lean4/pull/3796),
[#3800](https://github.com/leanprover/lean4/pull/3800), [#3874](https://github.com/leanprover/lean4/pull/3874),
[#3863](https://github.com/leanprover/lean4/pull/3863), [#3862](https://github.com/leanprover/lean4/pull/3862),
[#3891](https://github.com/leanprover/lean4/pull/3891), [#3873](https://github.com/leanprover/lean4/pull/3873),
[#3908](https://github.com/leanprover/lean4/pull/3908), [#3872](https://github.com/leanprover/lean4/pull/3872).
### Language server and IDE extensions
* [#3602](https://github.com/leanprover/lean4/pull/3602) enables `import` auto-completions.
* [#3608](https://github.com/leanprover/lean4/pull/3608) fixes issue [leanprover/vscode-lean4#392](https://github.com/leanprover/vscode-lean4/issues/392).
Diagnostic ranges had an off-by-one error that would misplace goal states for example.
* [#3014](https://github.com/leanprover/lean4/pull/3014) introduces snapshot trees, foundational work for incremental tactics and parallelism.
[#3849](https://github.com/leanprover/lean4/pull/3849) adds basic incrementality API.
* [#3271](https://github.com/leanprover/lean4/pull/3271) adds support for server-to-client requests.
* [#3656](https://github.com/leanprover/lean4/pull/3656) fixes jump to definition when there are conflicting names from different files.
Fixes issue [#1170](https://github.com/leanprover/lean4/issues/1170).
* [#3691](https://github.com/leanprover/lean4/pull/3691), [#3925](https://github.com/leanprover/lean4/pull/3925),
[#3932](https://github.com/leanprover/lean4/pull/3932) keep semantic tokens synchronized (used for semantic highlighting), with performance improvements.
* [#3247](https://github.com/leanprover/lean4/pull/3247) and [#3730](https://github.com/leanprover/lean4/pull/3730)
add diagnostics to run "Restart File" when a file dependency is saved.
* [#3722](https://github.com/leanprover/lean4/pull/3722) uses the correct module names when displaying references.
* [#3728](https://github.com/leanprover/lean4/pull/3728) makes errors in header reliably appear and makes the "Import out of date" warning be at "hint" severity.
[#3739](https://github.com/leanprover/lean4/pull/3739) simplifies the text of this warning.
* [#3778](https://github.com/leanprover/lean4/pull/3778) fixes [#3462](https://github.com/leanprover/lean4/issues/3462),
where info nodes from before the cursor would be used for computing completions.
* [#3985](https://github.com/leanprover/lean4/pull/3985) makes trace timings appear in Infoview.
### Pretty printing
* [#3797](https://github.com/leanprover/lean4/pull/3797) fixes the hovers over binders so that they show their types.
* [#3640](https://github.com/leanprover/lean4/pull/3640) and [#3735](https://github.com/leanprover/lean4/pull/3735): Adds attribute `@[pp_using_anonymous_constructor]` to make structures pretty print as `⟨x, y, z⟩`
rather than as `{a := x, b := y, c := z}`.
This attribute is applied to `Sigma`, `PSigma`, `PProd`, `Subtype`, `And`, and `Fin`.
* [#3749](https://github.com/leanprover/lean4/pull/3749)
Now structure instances pretty print with parent structures' fields inlined.
That is, if `B` extends `A`, then `{ toA := { x := 1 }, y := 2 }` now pretty prints as `{ x := 1, y := 2 }`.
Setting option `pp.structureInstances.flatten` to false turns this off.
* [#3737](https://github.com/leanprover/lean4/pull/3737), [#3744](https://github.com/leanprover/lean4/pull/3744)
and [#3750](https://github.com/leanprover/lean4/pull/3750):
Option `pp.structureProjections` is renamed to `pp.fieldNotation`, and there is now a suboption `pp.fieldNotation.generalized`
to enable pretty printing function applications using generalized field notation (defaults to true).
Field notation can be disabled on a function-by-function basis using the `@[pp_nodot]` attribute.
The notation is not used for theorems.
* [#4071](https://github.com/leanprover/lean4/pull/4071) fixes interaction between app unexpanders and `pp.fieldNotation.generalized`
* [#3625](https://github.com/leanprover/lean4/pull/3625) makes `delabConstWithSignature` (used by `#check`) have the ability to put arguments "after the colon"
to avoid printing inaccessible names.
* [#3798](https://github.com/leanprover/lean4/pull/3798),
[#3978](https://github.com/leanprover/lean4/pull/3978),
[#3798](https://github.com/leanprover/lean4/pull/3980):
Adds options `pp.mvars` (default: true) and `pp.mvars.withType` (default: false).
When `pp.mvars` is false, expression metavariables pretty print as `?_` and universe metavariables pretty print as `_`.
When `pp.mvars.withType` is true, expression metavariables pretty print with a type ascription.
These can be set when using `#guard_msgs` to make tests not depend on the particular names of metavariables.
* [#3917](https://github.com/leanprover/lean4/pull/3917) makes binders hoverable and gives them docstrings.
* [#4034](https://github.com/leanprover/lean4/pull/4034) makes hovers for RHS terms in `match` expressions in the Infoview reliably show the correct term.
### Library
* `Bool`/`Prop`
* [#3508](https://github.com/leanprover/lean4/pull/3508) improves `simp` confluence for `Bool` and `Prop` terms.
* Theorems: [#3604](https://github.com/leanprover/lean4/pull/3604)
* `Nat`
* [#3579](https://github.com/leanprover/lean4/pull/3579) makes `Nat.succ_eq_add_one` be a simp lemma, now that `induction`/`cases` uses `n + 1` instead of `Nat.succ n`.
* [#3808](https://github.com/leanprover/lean4/pull/3808) replaces `Nat.succ` simp rules with simprocs.
* [#3876](https://github.com/leanprover/lean4/pull/3876) adds faster `Nat.repr` implementation in C.
* `Int`
* Theorems: [#3890](https://github.com/leanprover/lean4/pull/3890)
* `UInt`s
* [#3960](https://github.com/leanprover/lean4/pull/3960) improves performance of upcasting.
* `Array` and `Subarray`
* [#3676](https://github.com/leanprover/lean4/pull/3676) removes `Array.eraseIdxAux`, `Array.eraseIdxSzAux`, and `Array.eraseIdx'`.
* [#3648](https://github.com/leanprover/lean4/pull/3648) simplifies `Array.findIdx?`.
* [#3851](https://github.com/leanprover/lean4/pull/3851) renames fields of `Subarray`.
* `List`
* [#3785](https://github.com/leanprover/lean4/pull/3785) upstreams tail-recursive List operations and `@[csimp]` lemmas.
* `BitVec`
* Theorems: [#3593](https://github.com/leanprover/lean4/pull/3593),
[#3593](https://github.com/leanprover/lean4/pull/3593), [#3597](https://github.com/leanprover/lean4/pull/3597),
[#3598](https://github.com/leanprover/lean4/pull/3598), [#3721](https://github.com/leanprover/lean4/pull/3721),
[#3729](https://github.com/leanprover/lean4/pull/3729), [#3880](https://github.com/leanprover/lean4/pull/3880),
[#4039](https://github.com/leanprover/lean4/pull/4039).
* [#3884](https://github.com/leanprover/lean4/pull/3884) protects `Std.BitVec`.
* `String`
* [#3832](https://github.com/leanprover/lean4/pull/3832) fixes `String.splitOn`.
* [#3959](https://github.com/leanprover/lean4/pull/3959) adds `String.Pos.isValid`.
* [#3959](https://github.com/leanprover/lean4/pull/3959) UTF-8 string validation.
* [#3961](https://github.com/leanprover/lean4/pull/3961) adds a model implementation for UTF-8 encoding and decoding.
* `IO`
* [#4097](https://github.com/leanprover/lean4/pull/4097) adds `IO.getTaskState` which returns whether a task is finished, actively running, or waiting on other Tasks to finish.
* **Refactors**
* [#3605](https://github.com/leanprover/lean4/pull/3605) reduces imports for `Init.Data.Nat` and `Init.Data.Int`.
* [#3613](https://github.com/leanprover/lean4/pull/3613) reduces imports for `Init.Omega.Int`.
* [#3634](https://github.com/leanprover/lean4/pull/3634) upstreams `Std.Data.Nat`
and [#3635](https://github.com/leanprover/lean4/pull/3635) upstreams `Std.Data.Int`.
* [#3790](https://github.com/leanprover/lean4/pull/3790) reduces more imports for `omega`.
* [#3694](https://github.com/leanprover/lean4/pull/3694) extends `GetElem` interface with `getElem!` and `getElem?` to simplify containers like `RBMap`.
* [#3865](https://github.com/leanprover/lean4/pull/3865) renames `Option.toMonad` (see breaking changes below).
* [#3882](https://github.com/leanprover/lean4/pull/3882) unifies `lexOrd` with `compareLex`.
* **Other fixes or improvements**
* [#3765](https://github.com/leanprover/lean4/pull/3765) makes `Quotient.sound` be a `theorem`.
* [#3645](https://github.com/leanprover/lean4/pull/3645) fixes `System.FilePath.parent` in the case of absolute paths.
* [#3660](https://github.com/leanprover/lean4/pull/3660) `ByteArray.toUInt64LE!` and `ByteArray.toUInt64BE!` were swapped.
* [#3881](https://github.com/leanprover/lean4/pull/3881), [#3887](https://github.com/leanprover/lean4/pull/3887) fix linearity issues in `HashMap.insertIfNew`, `HashSet.erase`, and `HashMap.erase`.
The `HashMap.insertIfNew` fix improves `import` performance.
* [#3830](https://github.com/leanprover/lean4/pull/3830) ensures linearity in `Parsec.many*Core`.
* [#3930](https://github.com/leanprover/lean4/pull/3930) adds `FS.Stream.isTty` field.
* [#3866](https://github.com/leanprover/lean4/pull/3866) deprecates `Option.toBool` in favor of `Option.isSome`.
* [#3975](https://github.com/leanprover/lean4/pull/3975) upstreams `Data.List.Init` and `Data.Array.Init` material from Std.
* [#3942](https://github.com/leanprover/lean4/pull/3942) adds instances that make `ac_rfl` work without Mathlib.
* [#4010](https://github.com/leanprover/lean4/pull/4010) changes `Fin.induction` to use structural induction.
* [02753f](https://github.com/leanprover/lean4/commit/02753f6e4c510c385efcbf71fa9a6bec50fce9ab)
fixes bug in `reduceLeDiff` simproc.
* [#4097](https://github.com/leanprover/lean4/pull/4097)
adds `IO.TaskState` and `IO.getTaskState` to get the task from the Lean runtime's task manager.
* **Docs:** [#3615](https://github.com/leanprover/lean4/pull/3615), [#3664](https://github.com/leanprover/lean4/pull/3664),
[#3707](https://github.com/leanprover/lean4/pull/3707), [#3734](https://github.com/leanprover/lean4/pull/3734),
[#3868](https://github.com/leanprover/lean4/pull/3868), [#3861](https://github.com/leanprover/lean4/pull/3861),
[#3869](https://github.com/leanprover/lean4/pull/3869), [#3858](https://github.com/leanprover/lean4/pull/3858),
[#3856](https://github.com/leanprover/lean4/pull/3856), [#3857](https://github.com/leanprover/lean4/pull/3857),
[#3867](https://github.com/leanprover/lean4/pull/3867), [#3864](https://github.com/leanprover/lean4/pull/3864),
[#3860](https://github.com/leanprover/lean4/pull/3860), [#3859](https://github.com/leanprover/lean4/pull/3859),
[#3871](https://github.com/leanprover/lean4/pull/3871), [#3919](https://github.com/leanprover/lean4/pull/3919).
### Lean internals
* **Defeq and WHNF algorithms**
* [#3616](https://github.com/leanprover/lean4/pull/3616) gives better support for reducing `Nat.rec` expressions.
* [#3774](https://github.com/leanprover/lean4/pull/3774) add tracing for "non-easy" WHNF cases.
* [#3807](https://github.com/leanprover/lean4/pull/3807) fixes an `isDefEq` performance issue, now trying structure eta *after* lazy delta reduction.
* [#3816](https://github.com/leanprover/lean4/pull/3816) fixes `.yesWithDeltaI` behavior to prevent increasing transparency level when reducing projections.
* [#3837](https://github.com/leanprover/lean4/pull/3837) improves heuristic at `isDefEq`.
* [#3965](https://github.com/leanprover/lean4/pull/3965) improves `isDefEq` for constraints of the form `t.i =?= s.i`.
* [#3977](https://github.com/leanprover/lean4/pull/3977) improves `isDefEqProj`.
* [#3981](https://github.com/leanprover/lean4/pull/3981) adds universe constraint approximations to be able to solve `u =?= max u ?v` using `?v = u`.
These approximations are only applied when universe constraints cannot be postponed anymore.
* [#4004](https://github.com/leanprover/lean4/pull/4004) improves `isDefEqProj` during typeclass resolution.
* [#4012](https://github.com/leanprover/lean4/pull/4012) adds `backward.isDefEq.lazyProjDelta` and `backward.isDefEq.lazyWhnfCore` backwards compatibility flags.
* **Kernel**
* [#3966](https://github.com/leanprover/lean4/pull/3966) removes dead code.
* [#4035](https://github.com/leanprover/lean4/pull/4035) fixes mismatch for `TheoremVal` between Lean and C++.
* **Discrimination trees**
* [423fed](https://github.com/leanprover/lean4/commit/423fed79a9de75705f34b3e8648db7e076c688d7)
and [3218b2](https://github.com/leanprover/lean4/commit/3218b25974d33e92807af3ce42198911c256ff1d):
simplify handling of dependent/non-dependent pi types.
* **Typeclass instance synthesis**
* [#3638](https://github.com/leanprover/lean4/pull/3638) eta-reduces synthesized instances
* [ce350f](https://github.com/leanprover/lean4/commit/ce350f348161e63fccde6c4a5fe1fd2070e7ce0f) fixes a linearity issue
* [917a31](https://github.com/leanprover/lean4/commit/917a31f694f0db44d6907cc2b1485459afe74d49)
improves performance by considering at most one answer for subgoals not containing metavariables.
[#4008](https://github.com/leanprover/lean4/pull/4008) adds `backward.synthInstance.canonInstances` backward compatibility flag.
* **Definition processing**
* [#3661](https://github.com/leanprover/lean4/pull/3661), [#3767](https://github.com/leanprover/lean4/pull/3767) changes automatically generated equational theorems to be named
using suffix `.eq_<idx>` instead of `._eq_<idx>`, and `.eq_def` instead of `._unfold`. (See breaking changes below.)
[#3675](https://github.com/leanprover/lean4/pull/3675) adds a mechanism to reserve names.
[#3803](https://github.com/leanprover/lean4/pull/3803) fixes reserved name resolution inside namespaces and fixes handling of `match`er declarations and equation lemmas.
* [#3662](https://github.com/leanprover/lean4/pull/3662) causes auxiliary definitions nested inside theorems to become `def`s if they are not proofs.
* [#4006](https://github.com/leanprover/lean4/pull/4006) makes proposition fields of `structure`s be theorems.
* [#4018](https://github.com/leanprover/lean4/pull/4018) makes it an error for a theorem to be `extern`.
* [#4047](https://github.com/leanprover/lean4/pull/4047) improves performance making equations for well-founded recursive definitions.
* **Refactors**
* [#3614](https://github.com/leanprover/lean4/pull/3614) avoids unfolding in `Lean.Meta.evalNat`.
* [#3621](https://github.com/leanprover/lean4/pull/3621) centralizes functionality for `Fix`/`GuessLex`/`FunInd` in the `ArgsPacker` module.
* [#3186](https://github.com/leanprover/lean4/pull/3186) rewrites the UnusedVariable linter to be more performant.
* [#3589](https://github.com/leanprover/lean4/pull/3589) removes coercion from `String` to `Name` (see breaking changes below).
* [#3237](https://github.com/leanprover/lean4/pull/3237) removes the `lines` field from `FileMap`.
* [#3951](https://github.com/leanprover/lean4/pull/3951) makes msg parameter to `throwTacticEx` optional.
* **Diagnostics**
* [#4016](https://github.com/leanprover/lean4/pull/4016), [#4019](https://github.com/leanprover/lean4/pull/4019),
[#4020](https://github.com/leanprover/lean4/pull/4020), [#4030](https://github.com/leanprover/lean4/pull/4030),
[#4031](https://github.com/leanprover/lean4/pull/4031),
[c3714b](https://github.com/leanprover/lean4/commit/c3714bdc6d46845c0428735b283c5b48b23cbcf7),
[#4049](https://github.com/leanprover/lean4/pull/4049) adds `set_option diagnostics true` for diagnostic counters.
Tracks number of unfolded declarations, instances, reducible declarations, used instances, recursor reductions,
`isDefEq` heuristic applications, among others.
This option is suggested in exceptional situations, such as at deterministic timeout and maximum recursion depth.
* [283587](https://github.com/leanprover/lean4/commit/283587987ab2eb3b56fbc3a19d5f33ab9e04a2ef)
adds diagnostic information for `simp`.
* [#4043](https://github.com/leanprover/lean4/pull/4043) adds diagnostic information for congruence theorems.
* [#4048](https://github.com/leanprover/lean4/pull/4048) display diagnostic information
for `set_option diagnostics true in <tactic>` and `set_option diagnostics true in <term>`.
* **Other features**
* [#3800](https://github.com/leanprover/lean4/pull/3800) adds environment extension to record which definitions use structural or well-founded recursion.
* [#3801](https://github.com/leanprover/lean4/pull/3801) `trace.profiler` can now export to Firefox Profiler.
* [#3918](https://github.com/leanprover/lean4/pull/3918), [#3953](https://github.com/leanprover/lean4/pull/3953) adds `@[builtin_doc]` attribute to make docs and location of a declaration available as a builtin.
* [#3939](https://github.com/leanprover/lean4/pull/3939) adds the `lean --json` CLI option to print messages as JSON.
* [#3075](https://github.com/leanprover/lean4/pull/3075) improves `test_extern` command.
* [#3970](https://github.com/leanprover/lean4/pull/3970) gives monadic generalization of `FindExpr`.
* **Docs:** [#3743](https://github.com/leanprover/lean4/pull/3743), [#3921](https://github.com/leanprover/lean4/pull/3921),
[#3954](https://github.com/leanprover/lean4/pull/3954).
* **Other fixes:** [#3622](https://github.com/leanprover/lean4/pull/3622),
[#3726](https://github.com/leanprover/lean4/pull/3726), [#3823](https://github.com/leanprover/lean4/pull/3823),
[#3897](https://github.com/leanprover/lean4/pull/3897), [#3964](https://github.com/leanprover/lean4/pull/3964),
[#3946](https://github.com/leanprover/lean4/pull/3946), [#4007](https://github.com/leanprover/lean4/pull/4007),
[#4026](https://github.com/leanprover/lean4/pull/4026).
### Compiler, runtime, and FFI
* [#3632](https://github.com/leanprover/lean4/pull/3632) makes it possible to allocate and free thread-local runtime resources for threads not started by Lean itself.
* [#3627](https://github.com/leanprover/lean4/pull/3627) improves error message about compacting closures.
* [#3692](https://github.com/leanprover/lean4/pull/3692) fixes deadlock in `IO.Promise.resolve`.
* [#3753](https://github.com/leanprover/lean4/pull/3753) catches error code from `MoveFileEx` on Windows.
* [#4028](https://github.com/leanprover/lean4/pull/4028) fixes a double `reset` bug in `ResetReuse` transformation.
* [6e731b](https://github.com/leanprover/lean4/commit/6e731b4370000a8e7a5cfb675a7f3d7635d21f58)
removes `interpreter` copy constructor to avoid potential memory safety issues.
### Lake
* **TOML Lake configurations**. [#3298](https://github.com/leanprover/lean4/pull/3298), [#4104](https://github.com/leanprover/lean4/pull/4104).
Lake packages can now use TOML as a alternative configuration file format instead of Lean. If the default `lakefile.lean` is missing, Lake will also look for a `lakefile.toml`. The TOML version of the configuration supports a restricted set of the Lake configuration options, only including those which can easily mapped to a TOML data structure. The TOML syntax itself fully compiles with the TOML v1.0.0 specification.
As part of the introduction of this new feature, we have been helping maintainers of some major packages within the ecosystem switch to this format. For example, the following is Aesop's new `lakefile.toml`:
**[leanprover-community/aesop/lakefile.toml](https://raw.githubusercontent.com/leanprover-community/aesop/de11e0ecf372976e6d627c210573146153090d2d/lakefile.toml)**
```toml
name = "aesop"
defaultTargets = ["Aesop"]
testRunner = "test"
precompileModules = false
[[require]]
name = "batteries"
git = "https://github.com/leanprover-community/batteries"
rev = "main"
[[lean_lib]]
name = "Aesop"
[[lean_lib]]
name = "AesopTest"
globs = ["AesopTest.+"]
leanOptions = {linter.unusedVariables = false}
[[lean_exe]]
name = "test"
srcDir = "scripts"
```
To assist users who wish to transition their packages between configuration file formats, there is also a new `lake translate-config` command for migrating to/from TOML.
Running `lake translate-config toml` will produce a `lakefile.toml` version of a package's `lakefile.lean`. Any configuration options unsupported by the TOML format will be discarded during translation, but the original `lakefile.lean` will remain so that you can verify the translation looks good before deleting it.
* **Build progress overhaul.** [#3835](https://github.com/leanprover/lean4/pull/3835), [#4115](https://github.com/leanprover/lean4/pull/4115), [#4127](https://github.com/leanprover/lean4/pull/4127), [#4220](https://github.com/leanprover/lean4/pull/4220), [#4232](https://github.com/leanprover/lean4/pull/4232), [#4236](https://github.com/leanprover/lean4/pull/4236).
Builds are now managed by a top-level Lake build monitor, this makes the output of Lake builds more standardized and enables producing prettier and more configurable progress reports.
As part of this change, job isolation has improved. Stray I/O and other build related errors in custom targets are now properly isolated and caught as part of their job. Import errors no longer cause Lake to abort the entire build and are instead localized to the build jobs of the modules in question.
Lake also now uses ANSI escape sequences to add color and produce progress lines that update in-place; this can be toggled on and off using `--ansi` / `--no-ansi`.
`--wfail` and `--iofail` options have been added that causes a build to fail if any of the jobs log a warning (`--wfail`) or produce any output or log information messages (`--iofail`). Unlike some other build systems, these options do **NOT** convert these logs into errors, and Lake does not abort jobs on such a log (i.e., dependent jobs will still continue unimpeded).
* `lake test`. [#3779](https://github.com/leanprover/lean4/pull/3779).
Lake now has a built-in `test` command which will run a script or executable labelled `@[test_runner]` (in Lean) or defined as the `testRunner` (in TOML) in the root package.
Lake also provides a `lake check-test` command which will exit with code `0` if the package has a properly configured test runner or error with `1` otherwise.
* `lake lean`. [#3793](https://github.com/leanprover/lean4/pull/3793).
The new command `lake lean <file> [-- <args...>]` functions like `lake env lean <file> <args...>`, except that it builds the imports of `file` before running `lean`. This makes it very useful for running test or example code that imports modules that are not guaranteed to have been built beforehand.
* **Miscellaneous bug fixes and improvements**
* [#3609](https://github.com/leanprover/lean4/pull/3609) `LEAN_GITHASH` environment variable to override the detected Git hash for Lean when computing traces, useful for testing custom builds of Lean.
* [#3795](https://github.com/leanprover/lean4/pull/3795) improves relative package directory path normalization in the pre-rename check.
* [#3957](https://github.com/leanprover/lean4/pull/3957) fixes handling of packages that appear multiple times in a dependency tree.
* [#3999](https://github.com/leanprover/lean4/pull/3999) makes it an error for there to be a mismatch between a package name and what it is required as. Also adds a special message for the `std`-to-`batteries` rename.
* [#4033](https://github.com/leanprover/lean4/pull/4033) fixes quiet mode.
* **Docs:** [#3704](https://github.com/leanprover/lean4/pull/3704).
### DevOps
* [#3536](https://github.com/leanprover/lean4/pull/3536) and [#3833](https://github.com/leanprover/lean4/pull/3833)
add a checklist for the release process.
* [#3600](https://github.com/leanprover/lean4/pull/3600) runs nix-ci more uniformly.
* [#3612](https://github.com/leanprover/lean4/pull/3612) avoids argument limits when building on Windows.
* [#3682](https://github.com/leanprover/lean4/pull/3682) builds Lean's `.o` files in parallel to rest of core.
* [#3601](https://github.com/leanprover/lean4/pull/3601)
changes the way Lean is built on Windows (see breaking changes below).
As a result, Lake now dynamically links executables with `supportInterpreter := true` on Windows
to `libleanshared.dll` and `libInit_shared.dll`. Therefore, such executables will not run
unless those shared libraries are co-located with the executables or part of `PATH`.
Running the executable via `lake exe` will ensure these libraries are part of `PATH`.
In a related change, the signature of the `nativeFacets` Lake configuration options has changed
from a static `Array` to a function `(shouldExport : Bool) → Array`.
See its docstring or Lake's [README](src/lake/README.md) for further details on the changed option.
* [#3690](https://github.com/leanprover/lean4/pull/3690) marks "Build matrix complete" as canceled if the build is canceled.
* [#3700](https://github.com/leanprover/lean4/pull/3700), [#3702](https://github.com/leanprover/lean4/pull/3702),
[#3701](https://github.com/leanprover/lean4/pull/3701), [#3834](https://github.com/leanprover/lean4/pull/3834),
[#3923](https://github.com/leanprover/lean4/pull/3923): fixes and improvements for std and mathlib CI.
* [#3712](https://github.com/leanprover/lean4/pull/3712) fixes `nix build .` on macOS.
* [#3717](https://github.com/leanprover/lean4/pull/3717) replaces `shell.nix` in devShell with `flake.nix`.
* [#3715](https://github.com/leanprover/lean4/pull/3715) and [#3790](https://github.com/leanprover/lean4/pull/3790) add test result summaries.
* [#3971](https://github.com/leanprover/lean4/pull/3971) prevents stage0 changes via the merge queue.
* [#3979](https://github.com/leanprover/lean4/pull/3979) adds handling for `changes-stage0` label.
* [#3952](https://github.com/leanprover/lean4/pull/3952) adds a script to summarize GitHub issues.
* [18a699](https://github.com/leanprover/lean4/commit/18a69914da53dbe37c91bc2b9ce65e1dc01752b6)
fixes asan linking
### Breaking changes
* Due to the major Lake build refactor, code using the affected parts of the Lake API or relying on the previous output format of Lake builds is likely to have been broken. We have tried to minimize the breakages and, where possible, old definitions have been marked `@[deprecated]` with a reference to the new alternative.
* Executables configured with `supportInterpreter := true` on Windows should now be run via `lake exe` to function properly.
* Automatically generated equational theorems are now named using suffix `.eq_<idx>` instead of `._eq_<idx>`, and `.eq_def` instead of `._unfold`. Example:
```
def fact : Nat → Nat
| 0 => 1
| n+1 => (n+1) * fact n
theorem ex : fact 0 = 1 := by unfold fact; decide
#check fact.eq_1
-- fact.eq_1 : fact 0 = 1
#check fact.eq_2
-- fact.eq_2 (n : Nat) : fact (Nat.succ n) = (n + 1) * fact n
#check fact.eq_def
/-
fact.eq_def :
∀ (x : Nat),
fact x =
match x with
| 0 => 1
| Nat.succ n => (n + 1) * fact n
-/
```
* The coercion from `String` to `Name` was removed. Previously, it was `Name.mkSimple`, which does not separate strings at dots, but experience showed that this is not always the desired coercion. For the previous behavior, manually insert a call to `Name.mkSimple`.
* The `Subarray` fields `as`, `h₁` and `h₂` have been renamed to `array`, `start_le_stop`, and `stop_le_array_size`, respectively. This more closely follows standard Lean conventions. Deprecated aliases for the field projections were added; these will be removed in a future release.
* The change to the instance name algorithm (described above) can break projects that made use of the auto-generated names.
* `Option.toMonad` has been renamed to `Option.getM` and the unneeded `[Monad m]` instance argument has been removed.
v4.7.0
---------
* `simp` and `rw` now use instance arguments found by unification,
rather than always resynthesizing. For backwards compatibility, the original behaviour is
available via `set_option tactic.skipAssignedInstances false`.
[#3507](https://github.com/leanprover/lean4/pull/3507) and
[#3509](https://github.com/leanprover/lean4/pull/3509).
* When the `pp.proofs` is false, now omitted proofs use `` rather than `_`,
which gives a more helpful error message when copied from the Infoview.
The `pp.proofs.threshold` option lets small proofs always be pretty printed.
[#3241](https://github.com/leanprover/lean4/pull/3241).
* `pp.proofs.withType` is now set to false by default to reduce noise in the info view.
* The pretty printer for applications now handles the case of over-application itself when applying app unexpanders.
In particular, the ``| `($_ $a $b $xs*) => `(($a + $b) $xs*)`` case of an `app_unexpander` is no longer necessary.
[#3495](https://github.com/leanprover/lean4/pull/3495).
* New `simp` (and `dsimp`) configuration option: `zetaDelta`. It is `false` by default.
The `zeta` option is still `true` by default, but their meaning has changed.
- When `zeta := true`, `simp` and `dsimp` reduce terms of the form
`let x := val; e[x]` into `e[val]`.
- When `zetaDelta := true`, `simp` and `dsimp` will expand let-variables in
the context. For example, suppose the context contains `x := val`. Then,
any occurrence of `x` is replaced with `val`.
See [issue #2682](https://github.com/leanprover/lean4/pull/2682) for additional details. Here are some examples:
```
example (h : z = 9) : let x := 5; let y := 4; x + y = z := by
intro x
simp
/-
New goal:
h : z = 9; x := 5 |- x + 4 = z
-/
rw [h]
example (h : z = 9) : let x := 5; let y := 4; x + y = z := by
intro x
-- Using both `zeta` and `zetaDelta`.
simp (config := { zetaDelta := true })
/-
New goal:
h : z = 9; x := 5 |- 9 = z
-/
rw [h]
example (h : z = 9) : let x := 5; let y := 4; x + y = z := by
intro x
simp [x] -- asks `simp` to unfold `x`
/-
New goal:
h : z = 9; x := 5 |- 9 = z
-/
rw [h]
example (h : z = 9) : let x := 5; let y := 4; x + y = z := by
intro x
simp (config := { zetaDelta := true, zeta := false })
/-
New goal:
h : z = 9; x := 5 |- let y := 4; 5 + y = z
-/
rw [h]
```
* When adding new local theorems to `simp`, the system assumes that the function application arguments
have been annotated with `no_index`. This modification, which addresses [issue #2670](https://github.com/leanprover/lean4/issues/2670),
restores the Lean 3 behavior that users expect. With this modification, the following examples are now operational:
```
example {α β : Type} {f : α × β → β → β} (h : ∀ p : α × β, f p p.2 = p.2)
(a : α) (b : β) : f (a, b) b = b := by
simp [h]
example {α β : Type} {f : α × β → β → β}
(a : α) (b : β) (h : f (a,b) (a,b).2 = (a,b).2) : f (a, b) b = b := by
simp [h]
```
In both cases, `h` is applicable because `simp` does not index f-arguments anymore when adding `h` to the `simp`-set.
It's important to note, however, that global theorems continue to be indexed in the usual manner.
* Improved the error messages produced by the `decide` tactic. [#3422](https://github.com/leanprover/lean4/pull/3422)
* Improved auto-completion performance. [#3460](https://github.com/leanprover/lean4/pull/3460)
* Improved initial language server startup performance. [#3552](https://github.com/leanprover/lean4/pull/3552)
* Changed call hierarchy to sort entries and strip private header from names displayed in the call hierarchy. [#3482](https://github.com/leanprover/lean4/pull/3482)
* There is now a low-level error recovery combinator in the parsing framework, primarily intended for DSLs. [#3413](https://github.com/leanprover/lean4/pull/3413)
* You can now write `termination_by?` after a declaration to see the automatically inferred
termination argument, and turn it into a `termination_by …` clause using the “Try this” widget or a code action. [#3514](https://github.com/leanprover/lean4/pull/3514)
* A large fraction of `Std` has been moved into the Lean repository.
This was motivated by:
1. Making universally useful tactics such as `ext`, `by_cases`, `change at`,
`norm_cast`, `rcases`, `simpa`, `simp?`, `omega`, and `exact?`
available to all users of Lean, without imports.
2. Minimizing the syntactic changes between plain Lean and Lean with `import Std`.
3. Simplifying the development process for the basic data types
`Nat`, `Int`, `Fin` (and variants such as `UInt64`), `List`, `Array`,
and `BitVec` as we begin making the APIs and simp normal forms for these types
more complete and consistent.
4. Laying the groundwork for the Std roadmap, as a library focused on
essential datatypes not provided by the core langauge (e.g. `RBMap`)
and utilities such as basic IO.
While we have achieved most of our initial aims in `v4.7.0-rc1`,
some upstreaming will continue over the coming months.
* The `/` and `%` notations in `Int` now use `Int.ediv` and `Int.emod`
(i.e. the rounding conventions have changed).
Previously `Std` overrode these notations, so this is no change for users of `Std`.
There is now kernel support for these functions.
[#3376](https://github.com/leanprover/lean4/pull/3376).
* `omega`, our integer linear arithmetic tactic, is now availabe in the core langauge.
* It is supplemented by a preprocessing tactic `bv_omega` which can solve goals about `BitVec`
which naturally translate into linear arithmetic problems.
[#3435](https://github.com/leanprover/lean4/pull/3435).
* `omega` now has support for `Fin` [#3427](https://github.com/leanprover/lean4/pull/3427),
the `<<<` operator [#3433](https://github.com/leanprover/lean4/pull/3433).
* During the port `omega` was modified to no longer identify atoms up to definitional equality
(so in particular it can no longer prove `id x ≤ x`). [#3525](https://github.com/leanprover/lean4/pull/3525).
This may cause some regressions.
We plan to provide a general purpose preprocessing tactic later, or an `omega!` mode.
* `omega` is now invoked in Lean's automation for termination proofs
[#3503](https://github.com/leanprover/lean4/pull/3503) as well as in
array indexing proofs [#3515](https://github.com/leanprover/lean4/pull/3515).
This automation will be substantially revised in the medium term,
and while `omega` does help automate some proofs, we plan to make this much more robust.
* The library search tactics `exact?` and `apply?` that were originally in
Mathlib are now available in Lean itself. These use the implementation using
lazy discrimination trees from `Std`, and thus do not require a disk cache but
have a slightly longer startup time. The order used for selection lemmas has
changed as well to favor goals purely based on how many terms in the head
pattern match the current goal.
* The `solve_by_elim` tactic has been ported from `Std` to Lean so that library
search can use it.
* New `#check_tactic` and `#check_simp` commands have been added. These are
useful for checking tactics (particularly `simp`) behave as expected in test
suites.
* Previously, app unexpanders would only be applied to entire applications. However, some notations produce
functions, and these functions can be given additional arguments. The solution so far has been to write app unexpanders so that they can take an arbitrary number of additional arguments. However this leads to misleading hover information in the Infoview. For example, while `HAdd.hAdd f g 1` pretty prints as `(f + g) 1`, hovering over `f + g` shows `f`. There is no way to fix the situation from within an app unexpander; the expression position for `HAdd.hAdd f g` is absent, and app unexpanders cannot register TermInfo.
This commit changes the app delaborator to try running app unexpanders on every prefix of an application, from longest to shortest prefix. For efficiency, it is careful to only try this when app delaborators do in fact exist for the head constant, and it also ensures arguments are only delaborated once. Then, in `(f + g) 1`, the `f + g` gets TermInfo registered for that subexpression, making it properly hoverable.
[#3375](https://github.com/leanprover/lean4/pull/3375)
Breaking changes:
* `Lean.withTraceNode` and variants got a stronger `MonadAlwaysExcept` assumption to
fix trace trees not being built on elaboration runtime exceptions. Instances for most elaboration
monads built on `EIO Exception` should be synthesized automatically.
* The `match ... with.` and `fun.` notations previously in Std have been replaced by
`nomatch ...` and `nofun`. [#3279](https://github.com/leanprover/lean4/pull/3279) and [#3286](https://github.com/leanprover/lean4/pull/3286)
Other improvements:
* several bug fixes for `simp`:
* we should not crash when `simp` loops [#3269](https://github.com/leanprover/lean4/pull/3269)
* `simp` gets stuck on `autoParam` [#3315](https://github.com/leanprover/lean4/pull/3315)
* `simp` fails when custom discharger makes no progress [#3317](https://github.com/leanprover/lean4/pull/3317)
* `simp` fails to discharge `autoParam` premises even when it can reduce them to `True` [#3314](https://github.com/leanprover/lean4/pull/3314)
* `simp?` suggests generated equations lemma names, fixes [#3547](https://github.com/leanprover/lean4/pull/3547) [#3573](https://github.com/leanprover/lean4/pull/3573)
* fixes for `match` expressions:
* fix regression with builtin literals [#3521](https://github.com/leanprover/lean4/pull/3521)
* accept `match` when patterns cover all cases of a `BitVec` finite type [#3538](https://github.com/leanprover/lean4/pull/3538)
* fix matching `Int` literals [#3504](https://github.com/leanprover/lean4/pull/3504)
* patterns containing int values and constructors [#3496](https://github.com/leanprover/lean4/pull/3496)
* improve `termination_by` error messages [#3255](https://github.com/leanprover/lean4/pull/3255)
* fix `rename_i` in macros, fixes [#3553](https://github.com/leanprover/lean4/pull/3553) [#3581](https://github.com/leanprover/lean4/pull/3581)
* fix excessive resource usage in `generalize`, fixes [#3524](https://github.com/leanprover/lean4/pull/3524) [#3575](https://github.com/leanprover/lean4/pull/3575)
* an equation lemma with autoParam arguments fails to rewrite, fixing [#2243](https://github.com/leanprover/lean4/pull/2243) [#3316](https://github.com/leanprover/lean4/pull/3316)
* `add_decl_doc` should check that declarations are local [#3311](https://github.com/leanprover/lean4/pull/3311)
* instantiate the types of inductives with the right parameters, closing [#3242](https://github.com/leanprover/lean4/pull/3242) [#3246](https://github.com/leanprover/lean4/pull/3246)
* New simprocs for many basic types. [#3407](https://github.com/leanprover/lean4/pull/3407)
Lake fixes:
* Warn on fetch cloud release failure [#3401](https://github.com/leanprover/lean4/pull/3401)
* Cloud release trace & `lake build :release` errors [#3248](https://github.com/leanprover/lean4/pull/3248)
v4.6.1
---------
* Backport of [#3552](https://github.com/leanprover/lean4/pull/3552) fixing a performance regression
in server startup.
v4.6.0
---------
* Add custom simplification procedures (aka `simproc`s) to `simp`. Simprocs can be triggered by the simplifier on a specified term-pattern. Here is an small example:
```lean
import Lean.Meta.Tactic.Simp.BuiltinSimprocs.Nat
```lean
import Lean.Meta.Tactic.Simp.BuiltinSimprocs.Nat
def foo (x : Nat) : Nat :=
x + 10
def foo (x : Nat) : Nat :=
x + 10
/--
The `simproc` `reduceFoo` is invoked on terms that match the pattern `foo _`.
-/
simproc reduceFoo (foo _) :=
/- A term of type `Expr → SimpM Step -/
fun e => do
/--
The `simproc` `reduceFoo` is invoked on terms that match the pattern `foo _`.
-/
simproc reduceFoo (foo _) :=
/- A term of type `Expr → SimpM Step -/
fun e => do
/-
The `Step` type has three constructors: `.done`, `.visit`, `.continue`.
* The constructor `.done` instructs `simp` that the result does
not need to be simplied further.
* The constructor `.visit` instructs `simp` to visit the resulting expression.
* The constructor `.continue` instructs `simp` to try other simplification procedures.
All three constructors take a `Result`. The `.continue` contructor may also take `none`.
`Result` has two fields `expr` (the new expression), and `proof?` (an optional proof).
If the new expression is definitionally equal to the input one, then `proof?` can be omitted or set to `none`.
-/
/- `simp` uses matching modulo reducibility. So, we ensure the term is a `foo`-application. -/
unless e.isAppOfArity ``foo 1 do
return .continue
/- `Nat.fromExpr?` tries to convert an expression into a `Nat` value -/
let some n ← Nat.fromExpr? e.appArg!
| return .continue
return .done { expr := Lean.mkNatLit (n+10) }
```
We disable simprocs support by using the command `set_option simprocs false`. This command is particularly useful when porting files to v4.6.0.
Simprocs can be scoped, manually added to `simp` commands, and suppressed using `-`. They are also supported by `simp?`. `simp only` does not execute any `simproc`. Here are some examples for the `simproc` defined above.
```lean
example : x + foo 2 = 12 + x := by
set_option simprocs false in
/- This `simp` command does not make progress since `simproc`s are disabled. -/
fail_if_success simp
simp_arith
example : x + foo 2 = 12 + x := by
/- `simp only` must not use the default simproc set. -/
fail_if_success simp only
simp_arith
example : x + foo 2 = 12 + x := by
/-
The `Step` type has three constructors: `.done`, `.visit`, `.continue`.
* The constructor `.done` instructs `simp` that the result does
not need to be simplied further.
* The constructor `.visit` instructs `simp` to visit the resulting expression.
* The constructor `.continue` instructs `simp` to try other simplification procedures.
`simp only` does not use the default simproc set,
but we can provide simprocs as arguments. -/
simp only [reduceFoo]
simp_arith
All three constructors take a `Result`. The `.continue` contructor may also take `none`.
`Result` has two fields `expr` (the new expression), and `proof?` (an optional proof).
If the new expression is definitionally equal to the input one, then `proof?` can be omitted or set to `none`.
-/
/- `simp` uses matching modulo reducibility. So, we ensure the term is a `foo`-application. -/
unless e.isAppOfArity ``foo 1 do
return .continue
/- `Nat.fromExpr?` tries to convert an expression into a `Nat` value -/
let some n Nat.fromExpr? e.appArg!
| return .continue
return .done { expr := Lean.mkNatLit (n+10) }
```
We disable simprocs support by using the command `set_option simprocs false`. This command is particularly useful when porting files to v4.6.0.
Simprocs can be scoped, manually added to `simp` commands, and suppressed using `-`. They are also supported by `simp?`. `simp only` does not execute any `simproc`. Here are some examples for the `simproc` defined above.
```lean
example : x + foo 2 = 12 + x := by
set_option simprocs false in
/- This `simp` command does not make progress since `simproc`s are disabled. -/
fail_if_success simp
simp_arith
example : x + foo 2 = 12 + x := by
/- `simp only` must not use the default simproc set. -/
fail_if_success simp only
simp_arith
example : x + foo 2 = 12 + x := by
/-
`simp only` does not use the default simproc set,
but we can provide simprocs as arguments. -/
simp only [reduceFoo]
simp_arith
example : x + foo 2 = 12 + x := by
/- We can use `-` to disable `simproc`s. -/
fail_if_success simp [-reduceFoo]
simp_arith
```
The command `register_simp_attr <id>` now creates a `simp` **and** a `simproc` set with the name `<id>`. The following command instructs Lean to insert the `reduceFoo` simplification procedure into the set `my_simp`. If no set is specified, Lean uses the default `simp` set.
```lean
simproc [my_simp] reduceFoo (foo _) := ...
```
example : x + foo 2 = 12 + x := by
/- We can use `-` to disable `simproc`s. -/
fail_if_success simp [-reduceFoo]
simp_arith
```
The command `register_simp_attr <id>` now creates a `simp` **and** a `simproc` set with the name `<id>`. The following command instructs Lean to insert the `reduceFoo` simplification procedure into the set `my_simp`. If no set is specified, Lean uses the default `simp` set.
```lean
simproc [my_simp] reduceFoo (foo _) := ...
```
* The syntax of the `termination_by` and `decreasing_by` termination hints is overhauled:
@@ -214,7 +906,7 @@ simproc [my_simp] reduceFoo (foo _) := ...
and hence greatly reduces the reliance on costly structure eta reduction. This has a large impact on mathlib,
reducing total CPU instructions by 3% and enabling impactful refactors like leanprover-community/mathlib4#8386
which reduces the build time by almost 20%.
See PR [#2478](https://github.com/leanprover/lean4/pull/2478) and RFC [#2451](https://github.com/leanprover/lean4/issues/2451).
See [PR #2478](https://github.com/leanprover/lean4/pull/2478) and [RFC #2451](https://github.com/leanprover/lean4/issues/2451).
* Add pretty printer settings to omit deeply nested terms (`pp.deepTerms false` and `pp.deepTerms.threshold`) ([PR #3201](https://github.com/leanprover/lean4/pull/3201))
@@ -233,7 +925,7 @@ Other improvements:
* produce simpler proof terms in `rw` [#3121](https://github.com/leanprover/lean4/pull/3121)
* fuse nested `mkCongrArg` calls in proofs generated by `simp` [#3203](https://github.com/leanprover/lean4/pull/3203)
* `induction using` followed by a general term [#3188](https://github.com/leanprover/lean4/pull/3188)
* allow generalization in `let` [#3060](https://github.com/leanprover/lean4/pull/3060, fixing [#3065](https://github.com/leanprover/lean4/issues/3065)
* allow generalization in `let` [#3060](https://github.com/leanprover/lean4/pull/3060), fixing [#3065](https://github.com/leanprover/lean4/issues/3065)
* reducing out-of-bounds `swap!` should return `a`, not `default`` [#3197](https://github.com/leanprover/lean4/pull/3197), fixing [#3196](https://github.com/leanprover/lean4/issues/3196)
* derive `BEq` on structure with `Prop`-fields [#3191](https://github.com/leanprover/lean4/pull/3191), fixing [#3140](https://github.com/leanprover/lean4/issues/3140)
* refine through more `casesOnApp`/`matcherApp` [#3176](https://github.com/leanprover/lean4/pull/3176), fixing [#3175](https://github.com/leanprover/lean4/pull/3175)

View File

@@ -1,9 +0,0 @@
# used for `nix-shell https://github.com/leanprover/lean4/archive/master.tar.gz -A nix`
{ nix = (import ./shell.nix {}).nix; } //
(import (
fetchTarball {
url = "https://github.com/edolstra/flake-compat/archive/c75e76f80c57784a6734356315b306140646ee84.tar.gz";
sha256 = "071aal00zp2m9knnhddgr2wqzlx6i6qa1263lv1y7bdn2w20h10h"; }
) {
src = ./.;
}).defaultNix

View File

@@ -1,4 +1,4 @@
open Std
open Batteries
open Lean
inductive BoolExpr where

View File

@@ -89,5 +89,6 @@
- [Testing](./dev/testing.md)
- [Debugging](./dev/debugging.md)
- [Commit Convention](./dev/commit_convention.md)
- [Release checklist](./dev/release_checklist.md)
- [Building This Manual](./dev/mdbook.md)
- [Foreign Function Interface](./dev/ffi.md)

View File

@@ -1 +1,11 @@
# Characters
A value of type `Char`, also known as a character, is a [Unicode scalar value](https://www.unicode.org/glossary/#unicode_scalar_value). It is represented using an unsigned 32-bit integer and is statically guaranteed to be a valid Unicode scalar value.
Syntactically, character literals are enclosed in single quotes.
```lean
#eval 'a' -- 'a'
#eval '' -- '∀'
```
Characters are ordered and can be decidably compared using the relational operators `=`, `<`, `≤`, `>`, `≥`.

View File

@@ -75,26 +75,28 @@ The github repository will automatically update stage0 on `master` once
If you have write access to the lean4 repository, you can also also manually
trigger that process, for example to be able to use new features in the compiler itself.
You can do that on <https://github.com/nomeata/lean4/actions/workflows/update-stage0.yml>
You can do that on <https://github.com/leanprover/lean4/actions/workflows/update-stage0.yml>
or using Github CLI with
```
gh workflow run update-stage0.yml
```
Leaving stage0 updates to the CI automation is preferrable, but should you need
to do it locally, you can use `make update-stage0` in `build/release`, to
update `stage0` from `stage1`, `make -C stageN update-stage0` to update from
another stage, or `nix run .#update-stage0-commit` to update using nix.
Leaving stage0 updates to the CI automation is preferable, but should you need
to do it locally, you can use `make update-stage0-commit` in `build/release` to
update `stage0` from `stage1` or `make -C stageN update-stage0-commit` to
update from another stage. This command will automatically stage the updated files
and introduce a commit,so make sure to commit your work before that.
If you rebased the branch (either onto a newer version of `master`, or fixing
up some commits prior to the stage0 update, recreate the stage0 update commits.
The script `script/rebase-stage0.sh` can be used for that.
The CI should prevent PRs with changes to stage0 (besides `stdlib_flags.h`)
from entering `master` through the (squashing!) merge queue, and label such PRs
with the `changes-stage0` label. Such PRs should have a cleaned up history,
with separate stage0 update commits; then coordinate with the admins to merge
your PR using rebase merge, bypassing the merge queue.
Updates to `stage0` should be their own commits in the Git history. So should
you have to include the stage0 update in your PR (rather than using above
automation after merging changes), commit your work before running `make
update-stage0`, commit the updated `stage0` compiler code with the commit
message:
```
chore: update stage0
```
and coordinate with the admins to not squash your PR.
## Further Bootstrapping Complications

View File

@@ -53,10 +53,59 @@ In the case of `@[extern]` all *irrelevant* types are removed first; see next se
Its runtime value is either a pointer to an opaque bignum object or, if the lowest bit of the "pointer" is 1 (`lean_is_scalar`), an encoded unboxed natural number (`lean_box`/`lean_unbox`).
* A universe `Sort u`, type constructor `... → Sort u`, or proposition `p : Prop` is *irrelevant* and is either statically erased (see above) or represented as a `lean_object *` with the runtime value `lean_box(0)`
* Any other type is represented by `lean_object *`.
Its runtime value is a pointer to an object of a subtype of `lean_object` (see respective declarations in `lean.h`) or the unboxed value `lean_box(cidx)` for the `cidx`th constructor of an inductive type if this constructor does not have any relevant parameters.
Its runtime value is a pointer to an object of a subtype of `lean_object` (see the "Inductive types" section below) or the unboxed value `lean_box(cidx)` for the `cidx`th constructor of an inductive type if this constructor does not have any relevant parameters.
Example: the runtime value of `u : Unit` is always `lean_box(0)`.
#### Inductive types
For inductive types which are in the fallback `lean_object *` case above and not trivial constructors, the type is stored as a `lean_ctor_object`, and `lean_is_ctor` will return true. A `lean_ctor_object` stores the constructor index in the header, and the fields are stored in the `m_objs` portion of the object.
The memory order of the fields is derived from the types and order of the fields in the declaration. They are ordered as follows:
* Non-scalar fields stored as `lean_object *`
* Fields of type `USize`
* Other scalar fields, in decreasing order by size
Within each group the fields are ordered in declaration order. **Warning**: Trivial wrapper types still count toward a field being treated as non-scalar for this purpose.
* To access fields of the first kind, use `lean_ctor_get(val, i)` to get the `i`th non-scalar field.
* To access `USize` fields, use `lean_ctor_get_usize(val, n+i)` to get the `i`th usize field and `n` is the total number of fields of the first kind.
* To access other scalar fields, use `lean_ctor_get_uintN(val, off)` or `lean_ctor_get_usize(val, off)` as appropriate. Here `off` is the byte offset of the field in the structure, starting at `n*sizeof(void*)` where `n` is the number of fields of the first two kinds.
For example, a structure such as
```lean
structure S where
ptr_1 : Array Nat
usize_1 : USize
sc64_1 : UInt64
ptr_2 : { x : UInt64 // x > 0 } -- wrappers don't count as scalars
sc64_2 : Float -- `Float` is 64 bit
sc8_1 : Bool
sc16_1 : UInt16
sc8_2 : UInt8
sc64_3 : UInt64
usize_2 : USize
ptr_3 : Char -- trivial wrapper around `UInt32`
sc32_1 : UInt32
sc16_2 : UInt16
```
would get re-sorted into the following memory order:
* `S.ptr_1` - `lean_ctor_get(val, 0)`
* `S.ptr_2` - `lean_ctor_get(val, 1)`
* `S.ptr_3` - `lean_ctor_get(val, 2)`
* `S.usize_1` - `lean_ctor_get_usize(val, 3)`
* `S.usize_2` - `lean_ctor_get_usize(val, 4)`
* `S.sc64_1` - `lean_ctor_get_uint64(val, sizeof(void*)*5)`
* `S.sc64_2` - `lean_ctor_get_float(val, sizeof(void*)*5 + 8)`
* `S.sc64_3` - `lean_ctor_get_uint64(val, sizeof(void*)*5 + 16)`
* `S.sc32_1` - `lean_ctor_get_uint32(val, sizeof(void*)*5 + 24)`
* `S.sc16_1` - `lean_ctor_get_uint16(val, sizeof(void*)*5 + 28)`
* `S.sc16_2` - `lean_ctor_get_uint16(val, sizeof(void*)*5 + 30)`
* `S.sc8_1` - `lean_ctor_get_uint8(val, sizeof(void*)*5 + 32)`
* `S.sc8_2` - `lean_ctor_get_uint8(val, sizeof(void*)*5 + 33)`
### Borrowing
By default, all `lean_object *` parameters of an `@[extern]` function are considered *owned*, i.e. the external code is passed a "virtual RC token" and is responsible for passing this token along to another consuming function (exactly once) or freeing it via `lean_dec`.
@@ -111,6 +160,15 @@ if (lean_io_result_is_ok(res)) {
lean_io_mark_end_initialization();
```
In addition, any other thread not spawned by the Lean runtime itself must be initialized for Lean use by calling
```c
void lean_initialize_thread();
```
and should be finalized in order to free all thread-local resources by calling
```c
void lean_finalize_thread();
```
## `@[extern]` in the Interpreter
The interpreter can run Lean declarations for which symbols are available in loaded shared libraries, which includes `@[extern]` declarations.

View File

@@ -74,3 +74,9 @@ Lean's build process uses [`ccache`](https://ccache.dev/) if it is
installed to speed up recompilation of the generated C code. Without
`ccache`, you'll likely spend more time than necessary waiting on
rebuilds - it's a good idea to make sure it's installed.
### `prelude`
Unlike most Lean projects, all submodules of the `Lean` module begin with the
`prelude` keyword. This disables the automated import of `Init`, meaning that
developers need to figure out their own subset of `Init` to import. This is done
such that changing files in `Init` doesn't force a full rebuild of `Lean`.

View File

@@ -0,0 +1,226 @@
# Releasing a stable version
This checklist walks you through releasing a stable version.
See below for the checklist for release candidates.
We'll use `v4.6.0` as the intended release version as a running example.
- One week before the planned release, ensure that someone has written the first draft of the release blog post
- `git checkout releases/v4.6.0`
(This branch should already exist, from the release candidates.)
- `git pull`
- In `src/CMakeLists.txt`, verify you see
- `set(LEAN_VERSION_MINOR 6)` (for whichever `6` is appropriate)
- `set(LEAN_VERSION_IS_RELEASE 1)`
- (both of these should already be in place from the release candidates)
- It is possible that the `v4.6.0` section of `RELEASES.md` is out of sync between
`releases/v4.6.0` and `master`. This should be reconciled:
- Run `git diff master RELEASES.md`.
- You should expect to see additons on `master` in the `v4.7.0-rc1` section; ignore these.
(i.e. the new release notes for the upcoming release candidate).
- Reconcile discrepancies in the `v4.6.0` section,
usually via copy and paste and a commit to `releases/v4.6.0`.
- `git tag v4.6.0`
- `git push $REMOTE v4.6.0`, where `$REMOTE` is the upstream Lean repository (e.g., `origin`, `upstream`)
- Now wait, while CI runs.
- You can monitor this at `https://github.com/leanprover/lean4/actions/workflows/ci.yml`,
looking for the `v4.6.0` tag.
- This step can take up to an hour.
- If you are intending to cut the next release candidate on the same day,
you may want to start on the release candidate checklist now.
- Go to https://github.com/leanprover/lean4/releases and verify that the `v4.6.0` release appears.
- Edit the release notes on Github to select the "Set as the latest release".
- Copy and paste the Github release notes from the previous releases candidate for this version
(e.g. `v4.6.0-rc1`), and quickly sanity check.
- Next, we will move a curated list of downstream repos to the latest stable release.
- For each of the repositories listed below:
- Make a PR to `master`/`main` changing the toolchain to `v4.6.0`
- Update the toolchain file
- In the Lakefile, if there are dependencies on specific version tags of dependencies that you've already pushed as part of this process, update them to the new tag.
If they depend on `main` or `master`, don't change this; you've just updated the dependency, so it will work and be saved in the manifest
- Run `lake update`
- The PR title should be "chore: bump toolchain to v4.6.0".
- Merge the PR once CI completes.
- Create the tag `v4.6.0` from `master`/`main` and push it.
- Merge the tag `v4.6.0` into the `stable` branch and push it.
- We do this for the repositories:
- [lean4checker](https://github.com/leanprover/lean4checker)
- No dependencies
- Toolchain bump PR
- Create and push the tag
- Merge the tag into `stable`
- [Batteries](https://github.com/leanprover-community/batteries)
- No dependencies
- Toolchain bump PR
- Create and push the tag
- Merge the tag into `stable`
- [ProofWidgets4](https://github.com/leanprover-community/ProofWidgets4)
- Dependencies: `Batteries`
- Note on versions and branches:
- `ProofWidgets` uses a sequential version tagging scheme, e.g. `v0.0.29`,
which does not refer to the toolchain being used.
- Make a new release in this sequence after merging the toolchain bump PR.
- `ProofWidgets` does not maintain a `stable` branch.
- Toolchain bump PR
- Create and push the tag, following the version convention of the repository
- [Aesop](https://github.com/leanprover-community/aesop)
- Dependencies: `Batteries`
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- Merge the tag into `stable`
- [doc-gen4](https://github.com/leanprover/doc-gen4)
- Dependencies: exist, but they're not part of the release workflow
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- There is no `stable` branch; skip this step
- [import-graph](https://github.com/leanprover-community/import-graph)
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- There is no `stable` branch; skip this step
- [Mathlib](https://github.com/leanprover-community/mathlib4)
- Dependencies: `Aesop`, `ProofWidgets4`, `lean4checker`, `Batteries`, `doc-gen4`, `import-graph`
- Toolchain bump PR notes:
- In addition to updating the `lean-toolchain` and `lakefile.lean`,
in `.github/workflows/lean4checker.yml` update the line
`git checkout v4.6.0` to the appropriate tag.
- Push the PR branch to the main Mathlib repository rather than a fork, or CI may not work reliably
- Create and push the tag
- Create a new branch from the tag, push it, and open a pull request against `stable`.
Coordinate with a Mathlib maintainer to get this merged.
- [REPL](https://github.com/leanprover-community/repl)
- Dependencies: `Mathlib` (for test code)
- Note that there are two copies of `lean-toolchain`/`lakefile.lean`:
in the root, and in `test/Mathlib/`. Edit both, and run `lake update` in both directories.
- Toolchain bump PR including updated Lake manifest
- Create and push the tag
- Merge the tag into `stable`
- Merge the release announcement PR for the Lean website - it will be deployed automatically
- Finally, make an announcement!
This should go in https://leanprover.zulipchat.com/#narrow/stream/113486-announce, with topic `v4.6.0`.
Please see previous announcements for suggested language.
You will want a few bullet points for main topics from the release notes.
Link to the blog post from the Zulip announcement.
- Make sure that whoever is handling social media knows the release is out.
## Optimistic(?) time estimates:
- Initial checks and push the tag: 30 minutes.
- Note that if `RELEASES.md` has discrepancies this could take longer!
- Waiting for the release: 60 minutes.
- Fixing release notes: 10 minutes.
- Bumping toolchains in downstream repositories, up to creating the Mathlib PR: 30 minutes.
- Waiting for Mathlib CI and bors: 120 minutes.
- Finalizing Mathlib tags and stable branch, and updating REPL: 15 minutes.
- Posting announcement and/or blog post: 20 minutes.
# Creating a release candidate.
This checklist walks you through creating the first release candidate for a version of Lean.
We'll use `v4.7.0-rc1` as the intended release version in this example.
- Decide which nightly release you want to turn into a release candidate.
We will use `nightly-2024-02-29` in this example.
- It is essential that Batteries and Mathlib already have reviewed branches compatible with this nightly.
- Check that both Batteries and Mathlib's `bump/v4.7.0` branch contain `nightly-2024-02-29`
in their `lean-toolchain`.
- The steps required to reach that state are beyond the scope of this checklist, but see below!
- Create the release branch from this nightly tag:
```
git remote add nightly https://github.com/leanprover/lean4-nightly.git
git fetch nightly tag nightly-2024-02-29
git checkout nightly-2024-02-29
git checkout -b releases/v4.7.0
```
- In `RELEASES.md` remove `(development in progress)` from the `v4.7.0` section header.
- Our current goal is to have written release notes only about major language features or breaking changes,
and to rely on automatically generated release notes for bugfixes and minor changes.
- Do not wait on `RELEASES.md` being perfect before creating the `release/v4.7.0` branch. It is essential to choose the nightly which will become the release candidate as early as possible, to avoid confusion.
- If there are major changes not reflected in `RELEASES.md` already, you may need to solicit help from the authors.
- Minor changes and bug fixes do not need to be documented in `RELEASES.md`: they will be added automatically on the Github release page.
- Commit your changes to `RELEASES.md`, and push.
- Remember that changes to `RELEASES.md` after you have branched `releases/v4.7.0` should also be cherry-picked back to `master`.
- In `src/CMakeLists.txt`,
- verify that you see `set(LEAN_VERSION_MINOR 7)` (for whichever `7` is appropriate); this should already have been updated when the development cycle began.
- `set(LEAN_VERSION_IS_RELEASE 1)` (this should be a change; on `master` and nightly releases it is always `0`).
- Commit your changes to `src/CMakeLists.txt`, and push.
- `git tag v4.7.0-rc1`
- `git push origin v4.7.0-rc1`
- Now wait, while CI runs.
- You can monitor this at `https://github.com/leanprover/lean4/actions/workflows/ci.yml`, looking for the `v4.7.0-rc1` tag.
- This step can take up to an hour.
- Once the release appears at https://github.com/leanprover/lean4/releases/
- Edit the release notes on Github to select the "Set as a pre-release box".
- Copy the section of `RELEASES.md` for this version into the Github release notes.
- Use the title "Changes since v4.6.0 (from RELEASES.md)"
- Then in the "previous tag" dropdown, select `v4.6.0`, and click "Generate release notes".
- This will add a list of all the commits since the last stable version.
- Delete anything already mentioned in the hand-written release notes above.
- Delete "update stage0" commits, and anything with a completely inscrutable commit message.
- Briefly rearrange the remaining items by category (e.g. `simp`, `lake`, `bug fixes`),
but for minor items don't put any work in expanding on commit messages.
- (How we want to release notes to look is evolving: please update this section if it looks wrong!)
- Next, we will move a curated list of downstream repos to the release candidate.
- This assumes that there is already a *reviewed* branch `bump/v4.7.0` on each repository
containing the required adaptations (or no adaptations are required).
The preparation of this branch is beyond the scope of this document.
- For each of the target repositories:
- Checkout the `bump/v4.7.0` branch.
- Verify that the `lean-toolchain` is set to the nightly from which the release candidate was created.
- `git merge origin/master`
- Change the `lean-toolchain` to `leanprover/lean4:v4.7.0-rc1`
- In `lakefile.lean`, change any dependencies which were using `nightly-testing` or `bump/v4.7.0` branches
back to `master` or `main`, and run `lake update` for those dependencies.
- Run `lake build` to ensure that dependencies are found (but it's okay to stop it after a moment).
- `git commit`
- `git push`
- Open a PR from `bump/v4.7.0` to `master`, and either merge it yourself after CI, if appropriate,
or notify the maintainers that it is ready to go.
- Once this PR has been merged, tag `master` with `v4.7.0-rc1` and push this tag.
- We do this for the same list of repositories as for stable releases, see above.
As above, there are dependencies between these, and so the process above is iterative.
It greatly helps if you can merge the `bump/v4.7.0` PRs yourself!
- For Batteries/Aesop/Mathlib, which maintain a `nightly-testing` branch, make sure there is a tag
`nightly-testing-2024-02-29` with date corresponding to the nightly used for the release
(create it if not), and then on the `nightly-testing` branch `git reset --hard master`, and force push.
- Make an announcement!
This should go in https://leanprover.zulipchat.com/#narrow/stream/113486-announce, with topic `v4.7.0-rc1`.
Please see previous announcements for suggested language.
You will want a few bullet points for main topics from the release notes.
Please also make sure that whoever is handling social media knows the release is out.
- Begin the next development cycle (i.e. for `v4.8.0`) on the Lean repository, by making a PR that:
- Updates `src/CMakeLists.txt` to say `set(LEAN_VERSION_MINOR 8)`
- Removes `(in development)` from the section heading in `RELEASES.md` for `v4.7.0`,
and creates a new `v4.8.0 (in development)` section heading.
## Time estimates:
Slightly longer than the corresponding steps for a stable release.
Similar process, but more things go wrong.
In particular, updating the downstream repositories is significantly more work
(because we need to merge existing `bump/v4.7.0` branches, not just update a toolchain).
# Preparing `bump/v4.7.0` branches
While not part of the release process per se,
this is a brief summary of the work that goes into updating Batteries/Aesop/Mathlib to new versions.
Please read https://leanprover-community.github.io/contribute/tags_and_branches.html
* Each repo has an unreviewed `nightly-testing` branch that
receives commits automatically from `master`, and
has its toolchain updated automatically for every nightly.
(Note: the aesop branch is not automated, and is updated on an as needed basis.)
As a consequence this branch is often broken.
A bot posts in the (private!) "Mathlib reviewers" stream on Zulip about the status of these branches.
* We fix the breakages by committing directly to `nightly-testing`: there is no PR process.
* This can either be done by the person managing this process directly,
or by soliciting assistance from authors of files, or generally helpful people on Zulip!
* Each repo has a `bump/v4.7.0` which accumulates reviewed changes adapting to new versions.
* Once `nightly-testing` is working on a given nightly, say `nightly-2024-02-15`, we:
* Make sure `bump/v4.7.0` is up to date with `master` (by merging `master`, no PR necessary)
* Create from `bump/v4.7.0` a `bump/nightly-2024-02-15` branch.
* In that branch, `git merge --squash nightly-testing` to bring across changes from `nightly-testing`.
* Sanity check changes, commit, and make a PR to `bump/v4.7.0` from the `bump/nightly-2024-02-15` branch.
* Solicit review, merge the PR into `bump/v4,7,0`.
* It is always okay to merge in the following directions:
`master` -> `bump/v4.7.0` -> `bump/nightly-2024-02-15` -> `nightly-testing`.
Please remember to push any merges you make to intermediate steps!

View File

@@ -4,16 +4,16 @@ def ack : Nat → Nat → Nat
| 0, y => y+1
| x+1, 0 => ack x 1
| x+1, y+1 => ack x (ack (x+1) y)
termination_by ack x y => (x, y)
termination_by x y => (x, y)
def sum (a : Array Int) : Int :=
let rec go (i : Nat) :=
if i < a.size then
if _ : i < a.size then
a[i] + go (i+1)
else
0
termination_by a.size - i
go 0
termination_by go i => a.size - i
set_option pp.proofs true
#print sum.go

View File

@@ -4,43 +4,42 @@ open Lean Meta
def ctor (mvarId : MVarId) (idx : Nat) : MetaM (List MVarId) := do
/- Set `MetaM` context using `mvarId` -/
withMVarContext mvarId do
mvarId.withContext do
/- Fail if the metavariable is already assigned. -/
checkNotAssigned mvarId `ctor
mvarId.checkNotAssigned `ctor
/- Retrieve the target type, instantiateMVars, and use `whnf`. -/
let target getMVarType' mvarId
let target mvarId.getType'
let .const declName us := target.getAppFn
| throwTacticEx `ctor mvarId "target is not an inductive datatype"
let .inductInfo { ctors, .. } getConstInfo declName
| throwTacticEx `ctor mvarId "target is not an inductive datatype"
if idx = 0 then
throwTacticEx `ctor mvarId "invalid index, it must be > 0"
throwTacticEx `ctor mvarId "invalid index, it must be > 0"
else if h : idx - 1 < ctors.length then
apply mvarId (.const ctors[idx - 1] us)
mvarId.apply (.const ctors[idx - 1] us)
else
throwTacticEx `ctor mvarId "invalid index, inductive datatype has only {ctors.length} contructors"
throwTacticEx `ctor mvarId "invalid index, inductive datatype has only {ctors.length} contructors"
open Elab Tactic
elab "ctor" idx:num : tactic =>
elab "ctor" idx:num : tactic =>
liftMetaTactic (ctor · idx.getNat)
example (p : Prop) : p := by
example (p : Prop) : p := by
ctor 1 -- Error
example (h : q) : p q := by
example (h : q) : p q := by
ctor 0 -- Error
exact h
example (h : q) : p q := by
example (h : q) : p q := by
ctor 3 -- Error
exact h
example (h : q) : p q := by
example (h : q) : p q := by
ctor 2
exact h
example (h : q) : p q := by
example (h : q) : p q := by
ctor 1
exact h -- Error
exact h -- Error

View File

@@ -5,15 +5,15 @@ open Lean Meta
def ex1 (declName : Name) : MetaM Unit := do
let info getConstInfo declName
IO.println s!"{declName} : {← ppExpr info.type}"
if let some val := info.value? then
if let some val := info.value? then
IO.println s!"{declName} : {← ppExpr val}"
#eval ex1 ``Nat
def ex2 (declName : Name) : MetaM Unit := do
let info getConstInfo declName
trace[Meta.debug] "{declName} : {info.type}"
if let some val := info.value? then
if let some val := info.value? then
trace[Meta.debug] "{declName} : {val}"
#eval ex2 ``Add.add
@@ -30,9 +30,9 @@ def ex3 (declName : Name) : MetaM Unit := do
trace[Meta.debug] "{x} : {← inferType x}"
def myMin [LT α] [DecidableRel (α := α) (·<·)] (a b : α) : α :=
if a < b then
if a < b then
a
else
else
b
set_option trace.Meta.debug true in
@@ -40,7 +40,7 @@ set_option trace.Meta.debug true in
def ex4 : MetaM Unit := do
let nat := mkConst ``Nat
withLocalDeclD `a nat fun a =>
withLocalDeclD `a nat fun a =>
withLocalDeclD `b nat fun b => do
let e mkAppM ``HAdd.hAdd #[a, b]
trace[Meta.debug] "{e} : {← inferType e}"
@@ -66,15 +66,17 @@ open Elab Term
def ex5 : TermElabM Unit := do
let nat := Lean.mkConst ``Nat
withLocalDeclD `a nat fun a => do
withLocalDeclD `a nat fun a => do
withLocalDeclD `b nat fun b => do
let ab mkAppM ``HAdd.hAdd #[a, b]
let stx `(fun x => if x < 10 then $( exprToSyntax ab) + x else x + $( exprToSyntax a))
let abStx exprToSyntax ab
let aStx exprToSyntax a
let stx `(fun x => if x < 10 then $abStx + x else x + $aStx)
let e elabTerm stx none
trace[Meta.debug] "{e} : {← inferType e}"
let e := mkApp e (mkNatLit 5)
let e whnf e
trace[Meta.debug] "{e}"
set_option trace.Meta.debug true in
#eval ex5

View File

@@ -4,16 +4,16 @@ def ack : Nat → Nat → Nat
| 0, y => y+1
| x+1, 0 => ack x 1
| x+1, y+1 => ack x (ack (x+1) y)
termination_by ack x y => (x, y)
termination_by x y => (x, y)
def sum (a : Array Int) : Int :=
let rec go (i : Nat) :=
if i < a.size then
if _ : i < a.size then
a[i] + go (i+1)
else
0
termination_by a.size - i
go 0
termination_by go i => a.size - i
set_option pp.proofs true
#print sum.go

View File

@@ -277,14 +277,13 @@ theorem BinTree.find_insert (b : BinTree β) (k : Nat) (v : β)
. by_cases' key < k
cases h; apply ihr; assumption
theorem BinTree.find_insert_of_ne (b : BinTree β) (h : k k') (v : β)
theorem BinTree.find_insert_of_ne (b : BinTree β) (ne : k k') (v : β)
: (b.insert k v).find? k' = b.find? k' := by
let t, h := b; simp
induction t with simp
| leaf =>
split <;> (try simp) <;> split <;> (try simp)
have_eq k k'
contradiction
intros le
exact Nat.lt_of_le_of_ne le ne
| node left key value right ihl ihr =>
let .node hl hr bl br := h
specialize ihl bl

1
doc/examples/compiler/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
build

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
source ../../tests/common.sh
exec_check lean -j 0 -Dlinter.all=false "$f"
exec_check lean -Dlinter.all=false "$f"

View File

@@ -27,7 +27,7 @@
src = inputs.mdBook;
cargoDeps = drv.cargoDeps.overrideAttrs (_: {
inherit src;
outputHash = "sha256-1YlPS6cqgxE4fjy9G8pWrpP27YrrbCDnfeyIsX81ZNw=";
outputHash = "sha256-CO3A9Kpp4sIvkT9X3p+GTidazk7Fn4jf0AP2PINN44A=";
});
doCheck = false;
});

View File

@@ -1,100 +0,0 @@
# -*- coding: utf-8 -*-
"""
pygments.lexers.theorem
~~~~~~~~~~~~~~~~~~~~~~~
Lexers for theorem-proving languages.
:copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
import re
from pygments.lexer import RegexLexer, default, words
from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
Number, Punctuation, Generic
__all__ = ['Lean4Lexer']
class Lean4Lexer(RegexLexer):
"""
For the `Lean 4 <https://github.com/leanprover/lean4>`_
theorem prover.
.. versionadded:: 2.0
"""
name = 'Lean4'
aliases = ['lean4']
filenames = ['*.lean']
mimetypes = ['text/x-lean']
flags = re.MULTILINE | re.UNICODE
keywords1 = (
'import', 'abbreviation', 'opaque_hint', 'tactic_hint', 'definition',
'renaming', 'inline', 'hiding', 'parameter', 'lemma', 'variable',
'theorem', 'axiom', 'inductive', 'structure', 'universe', 'alias',
'help', 'options', 'precedence', 'postfix', 'prefix',
'infix', 'infixl', 'infixr', 'notation', '#eval',
'#check', '#reduce', '#exit', 'coercion', 'end', 'private', 'using', 'namespace',
'including', 'instance', 'section', 'context', 'protected', 'expose',
'export', 'set_option', 'extends', 'open', 'example',
'constant', 'constants', 'print', 'opaque', 'reducible', 'irreducible',
'def', 'macro', 'elab', 'syntax', 'macro_rules', 'reduce', 'where',
'abbrev', 'noncomputable', 'class', 'attribute', 'synth', 'mutual',
)
keywords2 = (
'forall', 'fun', 'Pi', 'obtain', 'from', 'have', 'show', 'assume',
'take', 'let', 'if', 'else', 'then', 'by', 'in', 'with', 'begin',
'proof', 'qed', 'calc', 'match', 'nomatch', 'do', 'at',
)
keywords3 = (
# Sorts
'Type', 'Prop', 'Sort',
)
operators = (
u'!=', u'#', u'&', u'&&', u'*', u'+', u'-', u'/', u'@', u'!', u'`',
u'-.', u'->', u'.', u'..', u'...', u'::', u':>', u';', u';;', u'<',
u'<-', u'=', u'==', u'>', u'_', u'|', u'||', u'~', u'=>', u'<=', u'>=',
u'/\\', u'\\/', u'', u'Π', u'λ', u'', u'', u'', u'', u'', u'',
u'¬', u'⁻¹', u'', u'', u'', u'', u'', u'', u'', u'×', u'',
u'', u'', u'', u'',
)
punctuation = (u'(', u')', u':', u'{', u'}', u'[', u']', u'', u'',
u':=', u',')
tokens = {
'root': [
(r'\s+', Text),
(r'/-', Comment, 'comment'),
(r'--.*?$', Comment.Single),
(words(keywords1, prefix=r'\b', suffix=r'\b'), Keyword.Namespace),
(words(keywords2, prefix=r'\b', suffix=r'\b'), Keyword),
(words(keywords3, prefix=r'\b', suffix=r'\b'), Keyword.Type),
(words(operators), Name.Builtin.Pseudo),
(words(punctuation), Operator),
(u"[A-Za-z_\u03b1-\u03ba\u03bc-\u03fb\u1f00-\u1ffe\u2100-\u214f]"
u"[A-Za-z_'\u03b1-\u03ba\u03bc-\u03fb\u1f00-\u1ffe\u2070-\u2079"
u"\u207f-\u2089\u2090-\u209c\u2100-\u214f0-9]*", Name),
(r'\d+', Number.Integer),
(r'"', String.Double, 'string'),
(r'[~?][a-z][\w\']*:', Name.Variable)
],
'comment': [
# Multiline Comments
(r'[^/-]', Comment.Multiline),
(r'/-', Comment.Multiline, '#push'),
(r'-/', Comment.Multiline, '#pop'),
(r'[/-]', Comment.Multiline)
],
'string': [
(r'[^\\"]+', String.Double),
(r'\\[n"\\]', String.Escape),
('"', String.Double, '#pop'),
],
}

View File

@@ -1,3 +1,7 @@
These are instructions to set up a working development environment for those who wish to make changes to Lean itself. It is part of the [Development Guide](doc/dev/index.md).
We strongly suggest that new users instead follow the [Quickstart](doc/quickstart.md) to get started using Lean, since this sets up an environment that can automatically manage multiple Lean toolchain versions, which is necessary when working within the Lean ecosystem.
Requirements
------------
@@ -12,44 +16,32 @@ Platform-Specific Setup
- [Windows (msys2)](msys2.md)
- [Windows (WSL)](wsl.md)
- [macOS (homebrew)](osx-10.9.md)
- Linux/macOS/WSL via [Nix](https://nixos.org/nix/): Call `nix-shell` in the project root. That's it.
- Linux/macOS/WSL via [Nix](https://nixos.org/nix/): Call `nix develop` in the project root. That's it.
Generic Build Instructions
--------------------------
Setting up a basic release build:
Setting up a basic parallelized release build:
```bash
git clone https://github.com/leanprover/lean4 --recurse-submodules
git clone https://github.com/leanprover/lean4
cd lean4
mkdir -p build/release
cd build/release
cmake ../..
make
cmake --preset release
make -C build/release -j$(nproc) # see below for macOS
```
For regular development, we recommend running
```bash
git config submodule.recurse true
```
in the checkout so that `--recurse-submodules` doesn't have to be
specified with `git pull/checkout/...`.
You can replace `$(nproc)`, which is not available on macOS and some alternative shells, with the desired parallelism amount.
The above commands will compile the Lean library and binaries into the
`stage1` subfolder; see below for details. Add `-j N` for an
appropriate `N` to `make` for a parallel build.
`stage1` subfolder; see below for details.
For example, on an AMD Ryzen 9 `make` takes 00:04:55, whereas `make -j 10`
takes 00:01:38. Your results may vary depending on the speed of your hard
drive.
You should not usually run `make install` after a successful build.
You should not usually run `cmake --install` after a successful build.
See [Dev setup using elan](../dev/index.md#dev-setup-using-elan) on how to properly set up your editor to use the correct stage depending on the source directory.
Useful CMake Configuration Settings
-----------------------------------
Pass these along with the `cmake ../..` command.
Pass these along with the `cmake --preset release` command.
There are also two alternative presets that combine some of these options you can use instead of `release`: `debug` and `sandebug` (sanitize + debug).
* `-D CMAKE_BUILD_TYPE=`\
Select the build type. Valid values are `RELEASE` (default), `DEBUG`,

View File

@@ -1,39 +0,0 @@
# Compiling Lean with Visual Studio
WARNING: Compiling Lean with Visual Studio doesn't currently work.
There's an ongoing effort to port Lean to Visual Studio.
The instructions below are for VS 2017.
In the meantime you can use [MSYS2](msys2.md) or [WSL](wsl.md).
## Installing dependencies
First, install `vcpkg` from https://github.com/Microsoft/vcpkg if you haven't
done so already.
Then, open a console in the directory you cloned `vcpkg` to, and type:
`vcpkg install mpir` for the 32-bit library or
`vcpkg install mpir:x64-windows` for the x64 one.
In Visual Studio, use the "open folder" feature and open the Lean directory.
Go to the `CMake->Change CMake Settings` menu. File `CMakeSettings.json` opens.
In each of the targets, add the following snippet (i.e., after every
`ctestCommandArgs`):
```json
"variables": [
{
"name": "CMAKE_TOOLCHAIN_FILE",
"value": "C:\\path\\to\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake"
}
]
```
## Enable Intellisense
In Visual Studio, press Ctrl+Q and type `CppProperties.json` and press Enter.
Ensure `includePath` variables include `"${workspaceRoot}\\src"`.
## Build Lean
Press F7.

View File

@@ -38,10 +38,9 @@ cmake --version
Then follow the [generic build instructions](index.md) in the MSYS2
MinGW shell, using:
```
cmake ../.. -G "Unix Makefiles" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
cmake --preset release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
```
instead of `cmake ../..`. This ensures that cmake will call `sh` instead of `cmd.exe`
for script tasks and it will use the clang compiler instead of gcc, which is required.
instead of `cmake --preset release`. This will use the clang compiler instead of gcc, which is required with msys2.
## Install lean

View File

@@ -1,4 +1,4 @@
# Install Packages on OS X 10.9
# Install Packages on OS X 14.5
We assume that you are using [homebrew][homebrew] as a package manager.
@@ -22,7 +22,7 @@ brew install gcc
```
To install clang++-3.5 via homebrew, please execute:
```bash
brew install llvm --with-clang --with-asan
brew install llvm
```
To use compilers other than the default one (Apple's clang++), you
need to use `-DCMAKE_CXX_COMPILER` option to specify the compiler

View File

@@ -33,7 +33,7 @@ convert the pure non-monadic value `x / y` into the required `Except` object. S
Now this return typing would get tedious if you had to include it everywhere that you call this
function, however, Lean type inference can clean this up. For example, you can define a test
function can calls the `divide` function and you don't need to say anything here about the fact that
function that calls the `divide` function and you don't need to say anything here about the fact that
it might throw an error, because that is inferred:
-/
def test := divide 5 0

View File

@@ -15,7 +15,7 @@ data type containing several important pieces of information. First and foremost
current player, and it has a random generator.
-/
open Std (HashMap)
open Batteries (HashMap)
abbrev TileIndex := Nat × Nat -- a 2D index
inductive TileState where

View File

@@ -6,6 +6,7 @@ Platforms built & tested by our CI, available as binary releases via elan (see b
* x86-64 Linux with glibc 2.27+
* x86-64 macOS 10.15+
* aarch64 (Apple Silicon) macOS 10.15+
* x86-64 Windows 10+
### Tier 2
@@ -16,7 +17,6 @@ Releases may be silently broken due to the lack of automated testing.
Issue reports and fixes are welcome.
* aarch64 Linux with glibc 2.27+
* aarch64 (Apple Silicon) macOS
* x86 (32-bit) Linux
* Emscripten Web Assembly

View File

@@ -43,7 +43,8 @@ $ pdflatex test.tex
## Example with `minted`
First [install Pygments](https://pygments.org/download/). Then save [`lean4.py`](https://raw.githubusercontent.com/leanprover/lean4/master/doc/latex/lean4.py), which contains an version of the Lean highlighter updated for Lean 4, and the following sample LaTeX file `test.tex` into the same directory:
First [install Pygments](https://pygments.org/download/) (version 2.18 or newer).
Then save the following sample LaTeX file `test.tex` into the same directory:
```latex
\documentclass{article}
@@ -51,9 +52,8 @@ First [install Pygments](https://pygments.org/download/). Then save [`lean4.py`]
% switch to a monospace font supporting more Unicode characters
\setmonofont{FreeMono}
\usepackage{minted}
% instruct minted to use our local theorem.py
\newmintinline[lean]{lean4.py:Lean4Lexer -x}{bgcolor=white}
\newminted[leancode]{lean4.py:Lean4Lexer -x}{fontsize=\footnotesize}
\newmintinline[lean]{lean4}{bgcolor=white}
\newminted[leancode]{lean4}{fontsize=\footnotesize}
\usemintedstyle{tango} % a nice, colorful theme
\begin{document}
@@ -67,9 +67,6 @@ theorem funext {f₁ f₂ : ∀ (x : α), β x} (h : ∀ x, f₁ x = f₂ x) : f
\end{document}
```
If your version of `minted` is v2.7 or newer, but before v3.0,
you will additionally need to follow the workaround described in https://github.com/gpoore/minted/issues/360.
You can then compile `test.tex` by executing the following command:
```bash
@@ -81,11 +78,14 @@ Some remarks:
- either `xelatex` or `lualatex` is required to handle Unicode characters in the code.
- `--shell-escape` is needed to allow `xelatex` to execute `pygmentize` in a shell.
- If the chosen monospace font is missing some Unicode symbols, you can direct them to be displayed using a fallback font or other replacement LaTeX code.
``` latex
\usepackage{newunicodechar}
\newfontfamily{\freeserif}{DejaVu Sans}
\newunicodechar{✝}{\freeserif{✝}}
\newunicodechar{𝓞}{\ensuremath{\mathcal{O}}}
```
- minted has a "helpful" feature that draws red boxes around characters the chosen lexer doesn't recognize.
Since the Lean lexer cannot encompass all user-defined syntax, it is advisable to [work around](https://tex.stackexchange.com/a/343506/14563) this feature.
``` latex
\usepackage{newunicodechar}
\newfontfamily{\freeserif}{DejaVu Sans}
\newunicodechar{✝}{\freeserif{✝}}
\newunicodechar{𝓞}{\ensuremath{\mathcal{O}}}
```
- If you are using an old version of Pygments, you can copy
[`lean.py`](https://raw.githubusercontent.com/pygments/pygments/master/pygments/lexers/lean.py) into your working directory,
and use `lean4.py:Lean4Lexer -x` instead of `lean4` above.
If your version of `minted` is v2.7 or newer, but before v3.0,
you will additionally need to follow the workaround described in https://github.com/gpoore/minted/issues/360.

107
flake.lock generated
View File

@@ -1,12 +1,31 @@
{
"nodes": {
"flake-utils": {
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1656928814,
"narHash": "sha256-RIFfgBuKz6Hp89yRr7+NR5tzIAbn52h8vT6vXkYjZoM=",
"lastModified": 1673956053,
"narHash": "sha256-4gtG9iQuiKITOjNQQeQIpoIB6b16fm+504Ch3sNKLd8=",
"owner": "edolstra",
"repo": "flake-compat",
"rev": "35bb57c0c8d8b62bbfd284272c928ceb64ddbde9",
"type": "github"
},
"original": {
"owner": "edolstra",
"repo": "flake-compat",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1710146030,
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "7e2a3b3dfd9af950a856d66b0a7d01e3c18aa249",
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
@@ -18,11 +37,11 @@
"lean4-mode": {
"flake": false,
"locked": {
"lastModified": 1676498134,
"narHash": "sha256-u3WvyKxOViZG53hkb8wd2/Og6muTecbh+NdflIgVeyk=",
"lastModified": 1709737301,
"narHash": "sha256-uT9JN2kLNKJK9c/S/WxLjiHmwijq49EgLb+gJUSDpz0=",
"owner": "leanprover",
"repo": "lean4-mode",
"rev": "2c6ef33f476fdf5eb5e4fa4fa023ba8b11372440",
"rev": "f1f24c15134dee3754b82c9d9924866fe6bc6b9f",
"type": "github"
},
"original": {
@@ -31,34 +50,35 @@
"type": "github"
}
},
"lowdown-src": {
"libgit2": {
"flake": false,
"locked": {
"lastModified": 1633514407,
"narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
"owner": "kristapsdz",
"repo": "lowdown",
"rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
"lastModified": 1697646580,
"narHash": "sha256-oX4Z3S9WtJlwvj0uH9HlYcWv+x1hqp8mhXl7HsLu2f0=",
"owner": "libgit2",
"repo": "libgit2",
"rev": "45fd9ed7ae1a9b74b957ef4f337bc3c8b3df01b5",
"type": "github"
},
"original": {
"owner": "kristapsdz",
"repo": "lowdown",
"owner": "libgit2",
"repo": "libgit2",
"type": "github"
}
},
"nix": {
"inputs": {
"lowdown-src": "lowdown-src",
"flake-compat": "flake-compat",
"libgit2": "libgit2",
"nixpkgs": "nixpkgs",
"nixpkgs-regression": "nixpkgs-regression"
},
"locked": {
"lastModified": 1657097207,
"narHash": "sha256-SmeGmjWM3fEed3kQjqIAO8VpGmkC2sL1aPE7kKpK650=",
"lastModified": 1711102798,
"narHash": "sha256-CXOIJr8byjolqG7eqCLa+Wfi7rah62VmLoqSXENaZnw=",
"owner": "NixOS",
"repo": "nix",
"rev": "f6316b49a0c37172bca87ede6ea8144d7d89832f",
"rev": "a22328066416650471c3545b0b138669ea212ab4",
"type": "github"
},
"original": {
@@ -69,16 +89,33 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1653988320,
"narHash": "sha256-ZaqFFsSDipZ6KVqriwM34T739+KLYJvNmCWzErjAg7c=",
"lastModified": 1709083642,
"narHash": "sha256-7kkJQd4rZ+vFrzWu8sTRtta5D1kBG0LSRYAfhtmMlSo=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "2fa57ed190fd6c7c746319444f34b5917666e5c1",
"rev": "b550fe4b4776908ac2a861124307045f8e717c8e",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-22.05-small",
"ref": "release-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-old": {
"flake": false,
"locked": {
"lastModified": 1581379743,
"narHash": "sha256-i1XCn9rKuLjvCdu2UeXKzGLF6IuQePQKFt4hEKRU5oc=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "34c7eb7545d155cc5b6f499b23a7cb1c96ab4d59",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-19.03",
"repo": "nixpkgs",
"type": "github"
}
@@ -101,11 +138,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1686089707,
"narHash": "sha256-LTNlJcru2qJ0XhlhG9Acp5KyjB774Pza3tRH0pKIb3o=",
"lastModified": 1710889954,
"narHash": "sha256-Pr6F5Pmd7JnNEMHHmspZ0qVqIBVxyZ13ik1pJtm2QXk=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "af21c31b2a1ec5d361ed8050edd0303c31306397",
"rev": "7872526e9c5332274ea5932a0c3270d6e4724f3b",
"type": "github"
},
"original": {
@@ -120,7 +157,23 @@
"flake-utils": "flake-utils",
"lean4-mode": "lean4-mode",
"nix": "nix",
"nixpkgs": "nixpkgs_2"
"nixpkgs": "nixpkgs_2",
"nixpkgs-old": "nixpkgs-old"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},

View File

@@ -2,6 +2,9 @@
description = "Lean interactive theorem prover";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
# old nixpkgs used for portable release with older glibc (2.27)
inputs.nixpkgs-old.url = "github:NixOS/nixpkgs/nixos-19.03";
inputs.nixpkgs-old.flake = false;
inputs.flake-utils.url = "github:numtide/flake-utils";
inputs.nix.url = "github:NixOS/nix";
inputs.lean4-mode = {
@@ -17,14 +20,43 @@
# inputs.lean4-mode.follows = "lean4-mode";
#};
outputs = { self, nixpkgs, flake-utils, nix, lean4-mode, ... }@inputs: flake-utils.lib.eachDefaultSystem (system:
outputs = { self, nixpkgs, nixpkgs-old, flake-utils, nix, lean4-mode, ... }@inputs: flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
# for `vscode-with-extensions`
config.allowUnfree = true;
};
# An old nixpkgs for creating releases with an old glibc
pkgsDist-old = import nixpkgs-old { inherit system; };
# An old nixpkgs for creating releases with an old glibc
pkgsDist-old-aarch = import nixpkgs-old { localSystem.config = "aarch64-unknown-linux-gnu"; };
lean-packages = pkgs.callPackage (./nix/packages.nix) { src = ./.; inherit nix lean4-mode; };
devShellWithDist = pkgsDist: pkgs.mkShell.override {
stdenv = pkgs.overrideCC pkgs.stdenv lean-packages.llvmPackages.clang;
} ({
buildInputs = with pkgs; [
cmake gmp ccache
lean-packages.llvmPackages.llvm # llvm-symbolizer for asan/lsan
gdb
# TODO: only add when proven to not affect the flakification
#pkgs.python3
tree # for CI
];
# https://github.com/NixOS/nixpkgs/issues/60919
hardeningDisable = [ "all" ];
# more convenient `ctest` output
CTEST_OUTPUT_ON_FAILURE = 1;
} // pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
GMP = pkgsDist.gmp.override { withStatic = true; };
GLIBC = pkgsDist.glibc;
GLIBC_DEV = pkgsDist.glibc.dev;
GCC_LIB = pkgsDist.gcc.cc.lib;
ZLIB = pkgsDist.zlib;
GDB = pkgsDist.gdb;
});
in {
packages = lean-packages // rec {
debug = lean-packages.override { debug = true; };
@@ -49,7 +81,10 @@
};
defaultPackage = lean-packages.lean-all;
inherit (lean-packages) devShell;
# The default development shell for working on lean itself
devShells.default = devShellWithDist pkgs;
devShells.oldGlibc = devShellWithDist pkgsDist-old;
devShells.oldGlibcAArch = devShellWithDist pkgsDist-old-aarch;
checks.lean = lean-packages.test;
}) // rec {

View File

@@ -65,12 +65,7 @@ rec {
installPhase = ''
mkdir -p $out/bin $out/lib/lean
mv bin/lean $out/bin/
mv lib/lean/libleanshared.* $out/lib/lean
'' + lib.optionalString stdenv.isDarwin ''
for lib in $(otool -L $out/bin/lean | tail -n +2 | cut -d' ' -f1); do
if [[ "$lib" == *lean* ]]; then install_name_tool -change "$lib" "$out/lib/lean/$(basename $lib)" $out/bin/lean; fi
done
otool -L $out/bin/lean
mv lib/lean/*.{so,dylib} $out/lib/lean
'';
meta.mainProgram = "lean";
});
@@ -92,7 +87,8 @@ rec {
leanFlags = [ "-DwarningAsError=true" ];
} // args);
Init' = build { name = "Init"; deps = []; };
Lean' = build { name = "Lean"; deps = [ Init' ]; };
Std' = build { name = "Std"; deps = [ Init' ]; };
Lean' = build { name = "Lean"; deps = [ Std' ]; };
attachSharedLib = sharedLib: pkg: pkg // {
inherit sharedLib;
mods = mapAttrs (_: m: m // { inherit sharedLib; propagatedLoadDynlibs = []; }) pkg.mods;
@@ -100,7 +96,8 @@ rec {
in (all: all // all.lean) rec {
inherit (Lean) emacs-dev emacs-package vscode-dev vscode-package;
Init = attachSharedLib leanshared Init';
Lean = attachSharedLib leanshared Lean' // { allExternalDeps = [ Init ]; };
Std = attachSharedLib leanshared Std' // { allExternalDeps = [ Init ]; };
Lean = attachSharedLib leanshared Lean' // { allExternalDeps = [ Std ]; };
Lake = build {
name = "Lake";
src = src + "/src/lake";
@@ -114,35 +111,40 @@ rec {
linkFlags = lib.optional stdenv.isLinux "-rdynamic";
src = src + "/src/lake";
};
stdlib = [ Init Lean Lake ];
stdlib = [ Init Std Lean Lake ];
modDepsFiles = symlinkJoin { name = "modDepsFiles"; paths = map (l: l.modDepsFile) (stdlib ++ [ Leanc ]); };
depRoots = symlinkJoin { name = "depRoots"; paths = map (l: l.depRoots) stdlib; };
iTree = symlinkJoin { name = "ileans"; paths = map (l: l.iTree) stdlib; };
Leanc = build { name = "Leanc"; src = lean-bin-tools-unwrapped.leanc_src; deps = stdlib; roots = [ "Leanc" ]; };
stdlibLinkFlags = "-L${Init.staticLib} -L${Lean.staticLib} -L${Lake.staticLib} -L${leancpp}/lib/lean";
stdlibLinkFlags = "${lib.concatMapStringsSep " " (l: "-L${l.staticLib}") stdlib} -L${leancpp}/lib/lean";
libInit_shared = runCommand "libInit_shared" { buildInputs = [ stdenv.cc ]; libName = "libInit_shared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
mkdir $out
touch empty.c
${stdenv.cc}/bin/cc -shared -o $out/$libName empty.c
'';
leanshared = runCommand "leanshared" { buildInputs = [ stdenv.cc ]; libName = "libleanshared${stdenv.hostPlatform.extensions.sharedLibrary}"; } ''
mkdir $out
LEAN_CC=${stdenv.cc}/bin/cc ${lean-bin-tools-unwrapped}/bin/leanc -shared ${lib.optionalString stdenv.isLinux "-Wl,-Bsymbolic"} \
${if stdenv.isDarwin then "-Wl,-force_load,${Init.staticLib}/libInit.a -Wl,-force_load,${Lean.staticLib}/libLean.a -Wl,-force_load,${leancpp}/lib/lean/libleancpp.a ${leancpp}/lib/libleanrt_initial-exec.a -lc++"
else "-Wl,--whole-archive -lInit -lLean -lleancpp ${leancpp}/lib/libleanrt_initial-exec.a -Wl,--no-whole-archive -lstdc++"} -lm ${stdlibLinkFlags} \
${if stdenv.isDarwin then "-Wl,-force_load,${Init.staticLib}/libInit.a -Wl,-force_load,${Lean.staticLib}/libStd.a -Wl,-force_load,${Lean.staticLib}/libLean.a -Wl,-force_load,${leancpp}/lib/lean/libleancpp.a ${leancpp}/lib/libleanrt_initial-exec.a -lc++"
else "-Wl,--whole-archive -lInit -lStd -lLean -lleancpp ${leancpp}/lib/libleanrt_initial-exec.a -Wl,--no-whole-archive -lstdc++"} -lm ${stdlibLinkFlags} \
$(${llvmPackages.libllvm.dev}/bin/llvm-config --ldflags --libs) \
-o $out/$libName
'';
mods = foldl' (mods: pkg: mods // pkg.mods) {} stdlib;
print-paths = Lean.makePrintPathsFor [] mods;
leanc = writeShellScriptBin "leanc" ''
LEAN_CC=${stdenv.cc}/bin/cc ${Leanc.executable}/bin/leanc -I${lean-bin-tools-unwrapped}/include ${stdlibLinkFlags} -L${leanshared} "$@"
LEAN_CC=${stdenv.cc}/bin/cc ${Leanc.executable}/bin/leanc -I${lean-bin-tools-unwrapped}/include ${stdlibLinkFlags} -L${libInit_shared} -L${leanshared} "$@"
'';
lean = runCommand "lean" { buildInputs = lib.optional stdenv.isDarwin darwin.cctools; } ''
mkdir -p $out/bin
${leanc}/bin/leanc ${leancpp}/lib/lean.cpp.o ${leanshared}/* -o $out/bin/lean
${leanc}/bin/leanc ${leancpp}/lib/lean.cpp.o ${libInit_shared}/* ${leanshared}/* -o $out/bin/lean
'';
# derivation following the directory layout of the "basic" setup, mostly useful for running tests
lean-all = stdenv.mkDerivation {
name = "lean-${desc}";
buildCommand = ''
mkdir -p $out/bin $out/lib/lean
ln -sf ${leancpp}/lib/lean/* ${lib.concatMapStringsSep " " (l: "${l.modRoot}/* ${l.staticLib}/*") (lib.reverseList stdlib)} ${leanshared}/* $out/lib/lean/
ln -sf ${leancpp}/lib/lean/* ${lib.concatMapStringsSep " " (l: "${l.modRoot}/* ${l.staticLib}/*") (lib.reverseList stdlib)} ${libInit_shared}/* ${leanshared}/* $out/lib/lean/
# put everything in a single final derivation so `IO.appDir` references work
cp ${lean}/bin/lean ${leanc}/bin/leanc ${Lake-Main.executable}/bin/lake $out/bin
# NOTE: `lndir` will not override existing `bin/leanc`
@@ -150,11 +152,9 @@ rec {
'';
meta.mainProgram = "lean";
};
cacheRoots = linkFarmFromDrvs "cacheRoots" [
cacheRoots = linkFarmFromDrvs "cacheRoots" ([
stage0 lean leanc lean-all iTree modDepsFiles depRoots Leanc.src
# .o files are not a runtime dependency on macOS because of lack of thin archives
Lean.oTree Lake.oTree
];
] ++ map (lib: lib.oTree) stdlib);
test = buildCMake {
name = "lean-test-${desc}";
realSrc = lib.sourceByRegex src [ "src.*" "tests.*" ];
@@ -169,16 +169,17 @@ rec {
ln -sf ${lean-all}/* .
'';
buildPhase = ''
ctest --output-on-failure -E 'leancomptest_(doc_example|foreign)' -j$NIX_BUILD_CORES
ctest --output-junit test-results.xml --output-on-failure -E 'leancomptest_(doc_example|foreign)' -j$NIX_BUILD_CORES
'';
installPhase = ''
touch $out
mkdir $out
mv test-results.xml $out
'';
};
update-stage0 =
let cTree = symlinkJoin { name = "cs"; paths = [ Init.cTree Lean.cTree ]; }; in
let cTree = symlinkJoin { name = "cs"; paths = map (lib: lib.cTree) stdlib; }; in
writeShellScriptBin "update-stage0" ''
CSRCS=${cTree} CP_C_PARAMS="--dereference --no-preserve=all" ${src + "/script/update-stage0"}
CSRCS=${cTree} CP_C_PARAMS="--dereference --no-preserve=all" ${src + "/script/lib/update-stage0"}
'';
update-stage0-commit = writeShellScriptBin "update-stage0-commit" ''
set -euo pipefail

View File

@@ -5,12 +5,12 @@ let lean-final' = lean-final; in
lib.makeOverridable (
{ name, src, fullSrc ? src, srcPrefix ? "", srcPath ? "$PWD/${srcPrefix}",
# Lean dependencies. Each entry should be an output of buildLeanPackage.
deps ? [ lean.Lean ],
deps ? [ lean.Init lean.Std lean.Lean ],
# Static library dependencies. Each derivation `static` should contain a static library in the directory `${static}`.
staticLibDeps ? [],
# Whether to wrap static library inputs in a -Wl,--start-group [...] -Wl,--end-group to ensure dependencies are resolved.
groupStaticLibs ? false,
# Shared library dependencies included at interpretation with --load-dynlib and linked to. Each derivation `shared` should contain a
# Shared library dependencies included at interpretation with --load-dynlib and linked to. Each derivation `shared` should contain a
# shared library at the path `${shared}/${shared.libName or shared.name}` and a name to link to like `-l${shared.linkName or shared.name}`.
# These libs are also linked to in packages that depend on this one.
nativeSharedLibs ? [],
@@ -88,9 +88,9 @@ with builtins; let
allNativeSharedLibs =
lib.unique (lib.flatten (nativeSharedLibs ++ (map (dep: dep.allNativeSharedLibs or []) allExternalDeps)));
# A flattened list of all static library dependencies: this and every dep module's explicitly provided `staticLibDeps`,
# A flattened list of all static library dependencies: this and every dep module's explicitly provided `staticLibDeps`,
# plus every dep module itself: `dep.staticLib`
allStaticLibDeps =
allStaticLibDeps =
lib.unique (lib.flatten (staticLibDeps ++ (map (dep: [dep.staticLib] ++ dep.staticLibDeps or []) allExternalDeps)));
pathOfSharedLib = dep: dep.libPath or "${dep}/${dep.libName or dep.name}";
@@ -176,7 +176,7 @@ with builtins; let
# make local "copy" so `drv`'s Nix store path doesn't end up in ccache's hash
ln -s ${drv.c}/${drv.cPath} src.c
# on the other hand, a debug build is pretty fast anyway, so preserve the path for gdb
leanc -c -o $out/$oPath $leancFlags -fPIC ${if debug then "${drv.c}/${drv.cPath} -g" else "src.c -O3 -DNDEBUG"}
leanc -c -o $out/$oPath $leancFlags -fPIC ${if debug then "${drv.c}/${drv.cPath} -g" else "src.c -O3 -DNDEBUG -DLEAN_EXPORTING"}
'';
};
mkMod = mod: deps:

22
releases_drafts/README.md Normal file
View File

@@ -0,0 +1,22 @@
Draft release notes
-------------------
This folder contains drafts of release notes for inclusion in `RELEASES.md`.
During the process to create a release candidate, we look through all the commits that make up the release
to prepare the release notes, and in that process we take these drafts into account.
Guidelines:
- You should prefer adding release notes to commit messages over adding anything to this folder.
A release note should briefly explain the impact of a change from a user's point of view.
Please mark these parts out with words such as **release notes** and/or **breaking changes**.
- It is not necessary to add anything to this folder. It is meant for larger features that span multiple PRs,
or for anything that would be helpful when preparing the release notes that might be missed
by someone reading through the change log.
- If the PR that adds a feature simultaneously adds a draft release note, including the PR number is not required
since it can be obtained from the git history for the file.
When release notes are prepared, all the draft release notes are deleted from this folder.
For release candidates beyond the first one, you can either update `RELEASE.md` directly
or continue to add drafts.
When a release is finalized, we will copy the completed release notes from `RELEASE.md` to the `master` branch.

View File

@@ -0,0 +1,45 @@
A new linter flags situations where a local variable's name is one of
the argumentless constructors of its type. This can arise when a user either
doesn't open a namespace or doesn't add a dot or leading qualifier, as
in the following:
````
inductive Tree (α : Type) where
| leaf
| branch (left : Tree α) (val : α) (right : Tree α)
def depth : Tree α → Nat
| leaf => 0
````
With this linter, the `leaf` pattern is highlighted as a local
variable whose name overlaps with the constructor `Tree.leaf`.
The linter can be disabled with `set_option linter.constructorNameAsVariable false`.
Additionally, the error message that occurs when a name in a pattern that takes arguments isn't valid now suggests similar names that would be valid. This means that the following definition:
```
def length (list : List α) : Nat :=
match list with
| nil => 0
| cons x xs => length xs + 1
```
now results in the following warning:
```
warning: Local variable 'nil' resembles constructor 'List.nil' - write '.nil' (with a dot) or 'List.nil' to use the constructor.
note: this linter can be disabled with `set_option linter.constructorNameAsVariable false`
```
and error:
```
invalid pattern, constructor or constant marked with '[match_pattern]' expected
Suggestion: 'List.cons' is similar
```
#4301

View File

@@ -1,3 +1,8 @@
/-
Copyright (c) 2022 Sebastian Ullrich. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sebastian Ullrich
-/
import Lean.Runtime
abbrev M := ReaderT IO.FS.Stream IO
@@ -16,7 +21,7 @@ def mkTypedefFn (i : Nat) : M Unit := do
emit s!"typedef obj* (*fn{i})({args}); // NOLINT\n"
emit s!"#define FN{i}(f) reinterpret_cast<fn{i}>(lean_closure_fun(f))\n"
def genSeq (n : Nat) (f : Nat String) (sep := ", ") : String :=
def genSeq (n : Nat) (f : Nat String) (sep := ", ") : String :=
List.range n |>.map f |>.intersperse sep |> .join
-- make string: "obj* a1, obj* a2, ..., obj* an"

View File

@@ -0,0 +1,28 @@
import Lean.Util.Profiler
/-!
Usage:
```sh
lean --run ./script/collideProfiles.lean **/*.lean.json ... > merged.json
```
Merges multiple `trace.profiler.output` profiles into a single one while deduplicating samples with
the same stack. This is useful for building cumulative profiles of medium-to-large projects because
Firefox Profiler cannot handle hundreds of tracks and the deduplication will also ensure that the
profile is small enough for uploading.
As ordering of samples is not meaningful after this transformation, only "Call Tree" and "Flame
Graph" are useful for such profiles.
-/
open Lean
def main (args : List String) : IO Unit := do
let profiles args.toArray.mapM fun path => do
let json IO.FS.readFile path
let profile IO.ofExcept $ Json.parse json
IO.ofExcept <| fromJson? profile
-- NOTE: `collide` should not be interpreted
let profile := Firefox.Profile.collide profiles
IO.println <| Json.compress <| toJson profile

39
script/issues_summary.sh Normal file
View File

@@ -0,0 +1,39 @@
#!/bin/bash
# https://chat.openai.com/share/7469c7c3-aceb-4d80-aee5-62982e1f1538
# Output CSV Header
echo '"Issue URL","Title","Days Since Creation","Days Since Last Update","Total Reactions","Assignee","Labels"'
# Get the current date in YYYY-MM-DD format
today=$(date +%Y-%m-%d)
# Fetch only open issues (excluding PRs and closed issues) from the repository 'leanprover/lean4'
issues=$(gh api repos/leanprover/lean4/issues --paginate --jq '.[] | select(.pull_request == null and .state == "open") | {url: .html_url, title: .title, created_at: (.created_at | split("T")[0]), updated_at: (.updated_at | split("T")[0]), number: .number, assignee: (.assignee.login // ""), labels: [.labels[].name] | join(",")}')
# Process each JSON object
echo "$issues" | while IFS= read -r issue; do
# Extract fields from JSON
url=$(echo "$issue" | jq -r '.url')
title=$(echo "$issue" | jq -r '.title')
created_at=$(echo "$issue" | jq -r '.created_at')
updated_at=$(echo "$issue" | jq -r '.updated_at')
issue_number=$(echo "$issue" | jq -r '.number')
assignee=$(echo "$issue" | jq -r '.assignee')
labels=$(echo "$issue" | jq -r '.labels')
# Calculate days since creation and update using macOS compatible date calculation
days_since_created=$(( ($(date -jf "%Y-%m-%d" "$today" +%s) - $(date -jf "%Y-%m-%d" "$created_at" +%s)) / 86400 ))
days_since_updated=$(( ($(date -jf "%Y-%m-%d" "$today" +%s) - $(date -jf "%Y-%m-%d" "$updated_at" +%s)) / 86400 ))
# Fetch the total number of reactions for each issue
reaction_data=$(gh api repos/leanprover/lean4/issues/$issue_number/reactions --paginate --jq 'length' 2>&1)
if [[ $reaction_data == *"Not Found"* ]]; then
total_reactions="Error fetching reactions"
else
total_reactions=$reaction_data
fi
# Format output as CSV by escaping quotes and delimiting with commas
echo "\"$url\",\"${title//\"/\"\"}\",\"$days_since_created\",\"$days_since_updated\",\"$total_reactions\",\"$assignee\",\"$labels\""
done

2
script/lib/README.md Normal file
View File

@@ -0,0 +1,2 @@
This directory contains various scripts that are *not* meant to be called
directly, but through other scripts or makefiles.

19
script/lib/rebase-editor.sh Executable file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env bash
# Script internal to `./script/rebase-stage0.sh`
# Determine OS type for sed in-place editing
SED_CMD=("sed" "-i")
if [[ "$OSTYPE" == "darwin"* ]]
then
# macOS requires an empty string argument with -i for in-place editing
SED_CMD=("sed" "-i" "")
fi
if [ "$STAGE0_WITH_NIX" = true ]
then
"${SED_CMD[@]}" '/chore: update stage0/ s,.*,x nix run .#update-stage0-commit,' "$1"
else
"${SED_CMD[@]}" '/chore: update stage0/ s,.*,x make -j32 -C build/release update-stage0 \&\& git commit -m "chore: update stage0",' "$1"
fi

33
script/lib/update-stage0 Executable file
View File

@@ -0,0 +1,33 @@
#!/usr/bin/env bash
set -euo pipefail
rm -r stage0 || true
# don't copy untracked files
# `:!` is git glob flavor for exclude patterns
for f in $(git ls-files src ':!:src/lake/*' ':!:src/Leanc.lean'); do
if [[ $f == *.lean ]]; then
f=${f#src/}
f=${f%.lean}.c
mkdir -p $(dirname stage0/stdlib/$f)
cp ${CP_C_PARAMS:-} $CSRCS/$f stage0/stdlib/$f
else
mkdir -p $(dirname stage0/$f)
cp $f stage0/$f
fi
done
# special handling for Lake files due to its nested directory
# copy the README to ensure the `stage0/src/lake` directory is comitted
for f in $(git ls-files 'src/lake/Lake/*' src/lake/Lake.lean src/lake/README.md ':!:src/lakefile.toml'); do
if [[ $f == *.lean ]]; then
f=${f#src/lake}
f=${f%.lean}.c
mkdir -p $(dirname stage0/stdlib/$f)
cp ${CP_C_PARAMS:-} $CSRCS/$f stage0/stdlib/$f
else
mkdir -p $(dirname stage0/$f)
cp $f stage0/$f
fi
done
git add stage0

View File

@@ -25,6 +25,8 @@ cp -L llvm/bin/llvm-ar stage1/bin/
# dependencies of the above
$CP llvm/lib/lib{clang-cpp,LLVM}*.so* stage1/lib/
$CP $ZLIB/lib/libz.so* stage1/lib/
# general clang++ dependency, breaks cross-library C++ exceptions if linked statically
$CP $GCC_LIB/lib/libgcc_s.so* stage1/lib/
# bundle libatomic (referenced by LLVM >= 15, and required by the lean executable to run)
$CP $GCC_LIB/lib/libatomic.so* stage1/lib/
@@ -60,7 +62,7 @@ fi
# use `-nostdinc` to make sure headers are not visible by default (in particular, not to `#include_next` in the clang headers),
# but do not change sysroot so users can still link against system libs
echo -n " -DLEANC_INTERNAL_FLAGS='-nostdinc -isystem ROOT/include/clang' -DLEANC_CC=ROOT/bin/clang"
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/glibc ROOT/lib/glibc/libc_nonshared.a -Wl,--as-needed -static-libgcc -Wl,-Bstatic -lgmp -lunwind -Wl,-Bdynamic -Wl,--no-as-needed -fuse-ld=lld'"
echo -n " -DLEANC_INTERNAL_LINKER_FLAGS='-L ROOT/lib -L ROOT/lib/glibc ROOT/lib/glibc/libc_nonshared.a -Wl,--as-needed -Wl,-Bstatic -lgmp -lunwind -Wl,-Bdynamic -Wl,--no-as-needed -fuse-ld=lld'"
# when not using the above flags, link GMP dynamically/as usual
echo -n " -DLEAN_EXTRA_LINKER_FLAGS='-Wl,--as-needed -lgmp -Wl,--no-as-needed'"
# do not set `LEAN_CC` for tests

24
script/rebase-stage0.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/usr/bin/env bash
# This script rebases onto the given branch/commit, and updates
# all `chore: update stage0` commits along the way.
# Whether to use nix or make to update stage0
if [ "$1" = "-nix" ]
then
export STAGE0_WITH_NIX=true
shift
fi
# Check if an argument is provided
if [ "$#" -eq 0 ]; then
echo "Usage: $0 [-nix] <options to git rebase -i>"
exit 1
fi
REPO_ROOT=$(git rev-parse --show-toplevel)
# Run git rebase in interactive mode, but automatically edit the todo list
# using the defined GIT_SEQUENCE_EDITOR command
GIT_SEQUENCE_EDITOR="$REPO_ROOT/script/lib/rebase-editor.sh" git rebase -i "$@"

View File

@@ -1,18 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
rm -r stage0 || true
# don't copy untracked files
# `:!` is git glob flavor for exclude patterns
for f in $(git ls-files src ':!:src/lake/*' ':!:src/Leanc.lean'); do
if [[ $f == *.lean ]]; then
f=${f#src/}
f=${f%.lean}.c
mkdir -p $(dirname stage0/stdlib/$f)
cp ${CP_C_PARAMS:-} $CSRCS/$f stage0/stdlib/$f
else
mkdir -p $(dirname stage0/$f)
cp $f stage0/$f
fi
done
git add stage0

View File

@@ -1,27 +0,0 @@
let
flake = (import ./default.nix);
flakePkgs = flake.packages.${builtins.currentSystem};
in { pkgs ? flakePkgs.nixpkgs, pkgsDist ? pkgs }:
# use `shell` as default
(attribs: attribs.shell // attribs) rec {
shell = pkgs.mkShell.override {
stdenv = pkgs.overrideCC pkgs.stdenv flakePkgs.llvmPackages.clang;
} (rec {
buildInputs = with pkgs; [
cmake gmp ccache
flakePkgs.llvmPackages.llvm # llvm-symbolizer for asan/lsan
];
# https://github.com/NixOS/nixpkgs/issues/60919
hardeningDisable = [ "all" ];
# more convenient `ctest` output
CTEST_OUTPUT_ON_FAILURE = 1;
} // pkgs.lib.optionalAttrs pkgs.stdenv.isLinux {
GMP = pkgsDist.gmp.override { withStatic = true; };
GLIBC = pkgsDist.glibc;
GLIBC_DEV = pkgsDist.glibc.dev;
GCC_LIB = pkgsDist.gcc.cc.lib;
ZLIB = pkgsDist.zlib;
GDB = pkgsDist.gdb;
});
nix = flake.devShell.${builtins.currentSystem};
}

View File

@@ -9,7 +9,7 @@ endif()
include(ExternalProject)
project(LEAN CXX C)
set(LEAN_VERSION_MAJOR 4)
set(LEAN_VERSION_MINOR 7)
set(LEAN_VERSION_MINOR 10)
set(LEAN_VERSION_PATCH 0)
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
@@ -73,6 +73,7 @@ option(USE_GMP "USE_GMP" ON)
# development-specific options
option(CHECK_OLEAN_VERSION "Only load .olean files compiled with the current version of Lean" OFF)
option(USE_LAKE "Use Lake instead of lean.mk for building core libs from language server" OFF)
set(LEAN_EXTRA_MAKE_OPTS "" CACHE STRING "extra options to lean --make")
set(LEANC_CC ${CMAKE_C_COMPILER} CACHE STRING "C compiler to use in `leanc`")
@@ -299,13 +300,12 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
cmake_path(GET ZLIB_LIBRARY PARENT_PATH ZLIB_LIBRARY_PARENT_PATH)
string(APPEND LEANSHARED_LINKER_FLAGS " -L ${ZLIB_LIBRARY_PARENT_PATH}")
endif()
string(APPEND LEANC_STATIC_LINKER_FLAGS " -lleancpp -lInit -lLean -lleanrt")
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -lleancpp -lInit -lLean -lleanrt")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
string(APPEND LEANC_STATIC_LINKER_FLAGS " -lleancpp -lInit -lLean -lnodefs.js -lleanrt")
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -lleancpp -lInit -lLean -lnodefs.js -lleanrt")
else()
string(APPEND LEANC_STATIC_LINKER_FLAGS " -Wl,--start-group -lleancpp -lLean -Wl,--end-group -Wl,--start-group -lInit -lleanrt -Wl,--end-group")
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " -Wl,--start-group -lleancpp -lLean -Wl,--end-group -Wl,--start-group -lInit -lleanrt -Wl,--end-group")
endif()
string(APPEND LEANC_STATIC_LINKER_FLAGS " -lLake")
set(LEAN_CXX_STDLIB "-lstdc++" CACHE STRING "C++ stdlib linker flags")
@@ -313,8 +313,17 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(LEAN_CXX_STDLIB "-lc++")
endif()
string(APPEND LEANC_STATIC_LINKER_FLAGS " ${LEAN_CXX_STDLIB}")
string(APPEND LEANSHARED_LINKER_FLAGS " ${LEAN_CXX_STDLIB}")
string(APPEND TOOLCHAIN_STATIC_LINKER_FLAGS " ${LEAN_CXX_STDLIB} -lStd")
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " ${LEAN_CXX_STDLIB}")
# in local builds, link executables and not just dynlibs against C++ stdlib as well,
# which is required for e.g. asan
if(NOT LEAN_STANDALONE)
string(APPEND CMAKE_EXE_LINKER_FLAGS " ${LEAN_CXX_STDLIB}")
endif()
# flags for user binaries = flags for toolchain binaries + Lake
string(APPEND LEANC_STATIC_LINKER_FLAGS " ${TOOLCHAIN_STATIC_LINKER_FLAGS} -lLake")
if (LLVM)
string(APPEND LEANSHARED_LINKER_FLAGS " -L${LLVM_CONFIG_LIBDIR} ${LLVM_CONFIG_LDFLAGS} ${LLVM_CONFIG_LIBS} ${LLVM_CONFIG_SYSTEM_LIBS}")
@@ -342,9 +351,9 @@ endif()
# get rid of unused parts of C++ stdlib
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,-dead_strip")
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-dead_strip")
elseif(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,--gc-sections")
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,--gc-sections")
endif()
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
@@ -354,26 +363,20 @@ endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
if(BSYMBOLIC)
string(APPEND LEANC_SHARED_LINKER_FLAGS " -Wl,-Bsymbolic")
string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,-Bsymbolic")
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-Bsymbolic")
endif()
string(APPEND CMAKE_CXX_FLAGS " -fPIC -ftls-model=initial-exec")
string(APPEND LEANC_EXTRA_FLAGS " -fPIC")
string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,-rpath=\\$$ORIGIN/..:\\$$ORIGIN")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -lleanshared -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean")
string(APPEND TOOLCHAIN_SHARED_LINKER_FLAGS " -Wl,-rpath=\\$$ORIGIN/..:\\$$ORIGIN")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath=\\\$ORIGIN/../lib:\\\$ORIGIN/../lib/lean")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
string(APPEND CMAKE_CXX_FLAGS " -ftls-model=initial-exec")
string(APPEND INIT_SHARED_LINKER_FLAGS " -install_name @rpath/libInit_shared.dylib")
string(APPEND LEANSHARED_LINKER_FLAGS " -install_name @rpath/libleanshared.dylib")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -lleanshared -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,-rpath,@executable_path/../lib -Wl,-rpath,@executable_path/../lib/lean")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
string(APPEND CMAKE_CXX_FLAGS " -fPIC")
string(APPEND LEANC_EXTRA_FLAGS " -fPIC")
# We do not use dynamic linking via leanshared for Emscripten to keep things
# simple. (And we are not interested in `Lake` anyway.) To use dynamic
# linking, we would probably have to set MAIN_MODULE=2 on `leanshared`,
# SIDE_MODULE=2 on `lean`, and set CMAKE_SHARED_LIBRARY_SUFFIX to ".js".
string(APPEND CMAKE_EXE_LINKER_FLAGS " -Wl,--whole-archive -lInit -lLean -lleancpp -lleanrt ${EMSCRIPTEN_SETTINGS} -lnodefs.js -s EXIT_RUNTIME=1 -s MAIN_MODULE=1 -s LINKABLE=1 -s EXPORT_ALL=1")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
string(APPEND CMAKE_EXE_LINKER_FLAGS " -lleanshared")
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
@@ -399,7 +402,7 @@ endif()
# are already loaded) and probably fail unless we set up LD_LIBRARY_PATH.
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
# import library created by the `leanshared` target
string(APPEND LEANC_SHARED_LINKER_FLAGS " -lleanshared")
string(APPEND LEANC_SHARED_LINKER_FLAGS " -lInit_shared -lleanshared")
elseif("${CMAKE_SYSTEM_NAME}" MATCHES "Darwin")
string(APPEND LEANC_SHARED_LINKER_FLAGS " -Wl,-undefined,dynamic_lookup")
endif()
@@ -505,13 +508,25 @@ string(REGEX REPLACE "^([a-zA-Z]):" "/\\1" LEAN_BIN "${CMAKE_BINARY_DIR}/bin")
# (also looks nicer in the build log)
file(RELATIVE_PATH LIB ${LEAN_SOURCE_DIR} ${CMAKE_BINARY_DIR}/lib)
# set up libInit_shared only on Windows; see also stdlib.make.in
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(INIT_SHARED_LINKER_FLAGS "-Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libInit.a.export ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a -Wl,--no-whole-archive -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libInit_shared.dll.a")
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(LEANSHARED_LINKER_FLAGS "-Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libInit.a -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libLean.a -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libleancpp.a ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a ${LEANSHARED_LINKER_FLAGS}")
set(LEANSHARED_LINKER_FLAGS "-Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libInit.a -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libStd.a -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libLean.a -Wl,-force_load,${CMAKE_BINARY_DIR}/lib/lean/libleancpp.a ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a ${LEANSHARED_LINKER_FLAGS}")
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(LEANSHARED_LINKER_FLAGS "-Wl,--whole-archive ${CMAKE_BINARY_DIR}/lib/temp/libStd.a.export ${CMAKE_BINARY_DIR}/lib/temp/libLean.a.export -lleancpp -Wl,--no-whole-archive -lInit_shared -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libleanshared.dll.a")
else()
set(LEANSHARED_LINKER_FLAGS "-Wl,--whole-archive -lInit -lLean -lleancpp -Wl,--no-whole-archive ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a ${LEANSHARED_LINKER_FLAGS}")
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
string(APPEND LEANSHARED_LINKER_FLAGS " -Wl,--out-implib,${CMAKE_BINARY_DIR}/lib/lean/libleanshared.dll.a")
endif()
set(LEANSHARED_LINKER_FLAGS "-Wl,--whole-archive -lInit -lStd -lLean -lleancpp -Wl,--no-whole-archive ${CMAKE_BINARY_DIR}/runtime/libleanrt_initial-exec.a ${LEANSHARED_LINKER_FLAGS}")
endif()
if (${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
# We do not use dynamic linking via leanshared for Emscripten to keep things
# simple. (And we are not interested in `Lake` anyway.) To use dynamic
# linking, we would probably have to set MAIN_MODULE=2 on `leanshared`,
# SIDE_MODULE=2 on `lean`, and set CMAKE_SHARED_LIBRARY_SUFFIX to ".js".
string(APPEND LEAN_EXE_LINKER_FLAGS " ${TOOLCHAIN_STATIC_LINKER_FLAGS} ${EMSCRIPTEN_SETTINGS} -lnodefs.js -s EXIT_RUNTIME=1 -s MAIN_MODULE=1 -s LINKABLE=1 -s EXPORT_ALL=1")
endif()
# Build the compiler using the bootstrapped C sources for stage0, and use
@@ -520,16 +535,12 @@ if (LLVM AND ${STAGE} GREATER 0)
set(EXTRA_LEANMAKE_OPTS "LLVM=1")
endif()
# Escape for `make`. Yes, twice.
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE "${CMAKE_EXE_LINKER_FLAGS}")
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE "${CMAKE_EXE_LINKER_FLAGS_MAKE}")
configure_file(${LEAN_SOURCE_DIR}/stdlib.make.in ${CMAKE_BINARY_DIR}/stdlib.make)
add_custom_target(make_stdlib ALL
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
# The actual rule is in a separate makefile because we want to prefix it with '+' to use the Make job server
# for a parallelized nested build, but CMake doesn't let us do that.
# We use `lean` from the previous stage, but `leanc`, headers, etc. from the current stage
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Init Lean
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Init Std Lean
VERBATIM)
# if we have LLVM enabled, then build `lean.h.bc` which has the LLVM bitcode
@@ -541,17 +552,33 @@ endif()
# We declare these as separate custom targets so they use separate `make` invocations, which makes `make` recompute which dependencies
# (e.g. `libLean.a`) are now newer than the target file
add_custom_target(leanshared ALL
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
DEPENDS make_stdlib leancpp leanrt_initial-exec
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make leanshared
VERBATIM)
if(${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
# dummy targets, see `MAIN_MODULE` discussion above
add_custom_target(Init_shared ALL
DEPENDS make_stdlib leanrt_initial-exec
COMMAND touch ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libInit_shared${CMAKE_SHARED_LIBRARY_SUFFIX}
)
add_custom_target(leanshared ALL
DEPENDS Init_shared leancpp
COMMAND touch ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libleanshared${CMAKE_SHARED_LIBRARY_SUFFIX}
)
else()
add_custom_target(Init_shared ALL
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
DEPENDS make_stdlib leanrt_initial-exec
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make Init_shared
VERBATIM)
if(${STAGE} GREATER 0)
if(NOT EXISTS ${LEAN_SOURCE_DIR}/lake/Lake.lean)
message(FATAL_ERROR "src/lake does not exist. Please check out the Lake submodule using `git submodule update --init src/lake`.")
endif()
add_custom_target(leanshared ALL
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
DEPENDS Init_shared leancpp
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make leanshared
VERBATIM)
string(APPEND CMAKE_EXE_LINKER_FLAGS " -lInit_shared -lleanshared")
endif()
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
add_custom_target(lake ALL
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
DEPENDS leanshared
@@ -561,14 +588,18 @@ endif()
if(PREV_STAGE)
add_custom_target(update-stage0
COMMAND bash -c 'CSRCS=${CMAKE_BINARY_DIR}/lib/temp script/update-stage0'
COMMAND bash -c 'CSRCS=${CMAKE_BINARY_DIR}/lib/temp script/lib/update-stage0'
DEPENDS make_stdlib
WORKING_DIRECTORY "${LEAN_SOURCE_DIR}/..")
add_custom_target(update-stage0-commit
COMMAND git commit -m "chore: update stage0"
DEPENDS update-stage0)
endif()
# use Bash version for building, use Lean version in bin/ for tests & distribution
configure_file("${LEAN_SOURCE_DIR}/bin/leanc.in" "${CMAKE_BINARY_DIR}/leanc.sh" @ONLY)
if(${STAGE} GREATER 0 AND EXISTS ${LEAN_SOURCE_DIR}/Leanc.lean)
if(${STAGE} GREATER 0 AND EXISTS ${LEAN_SOURCE_DIR}/Leanc.lean AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
configure_file("${LEAN_SOURCE_DIR}/Leanc.lean" "${CMAKE_BINARY_DIR}/leanc/Leanc.lean" @ONLY)
add_custom_target(leanc ALL
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/leanc
@@ -619,3 +650,14 @@ if(LEAN_INSTALL_PREFIX)
set(LEAN_INSTALL_SUFFIX "-${LOWER_SYSTEM_NAME}" CACHE STRING "If LEAN_INSTALL_PREFIX is set, append this value to CMAKE_INSTALL_PREFIX")
set(CMAKE_INSTALL_PREFIX "${LEAN_INSTALL_PREFIX}/lean-${LEAN_VERSION_STRING}${LEAN_INSTALL_SUFFIX}")
endif()
# Escape for `make`. Yes, twice.
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE "${CMAKE_EXE_LINKER_FLAGS}")
string(REPLACE "$" "$$" CMAKE_EXE_LINKER_FLAGS_MAKE_MAKE "${CMAKE_EXE_LINKER_FLAGS_MAKE}")
configure_file(${LEAN_SOURCE_DIR}/stdlib.make.in ${CMAKE_BINARY_DIR}/stdlib.make)
if(USE_LAKE AND STAGE EQUAL 1)
configure_file(${LEAN_SOURCE_DIR}/lakefile.toml.in ${LEAN_SOURCE_DIR}/lakefile.toml)
configure_file(${LEAN_SOURCE_DIR}/lakefile.toml.in ${LEAN_SOURCE_DIR}/../tests/lakefile.toml)
configure_file(${LEAN_SOURCE_DIR}/lakefile.toml.in ${LEAN_SOURCE_DIR}/../lakefile.toml)
endif()

View File

@@ -7,6 +7,9 @@ prelude
import Init.Prelude
import Init.Notation
import Init.Tactics
import Init.TacticsExtra
import Init.ByCases
import Init.RCases
import Init.Core
import Init.Control
import Init.Data.Basic
@@ -21,7 +24,14 @@ import Init.MetaTypes
import Init.Meta
import Init.NotationExtra
import Init.SimpLemmas
import Init.PropLemmas
import Init.Hints
import Init.Conv
import Init.Guard
import Init.Simproc
import Init.SizeOfLemmas
import Init.BinderPredicates
import Init.Ext
import Init.Omega
import Init.MacroTrace
import Init.Grind

View File

@@ -0,0 +1,82 @@
/-
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Gabriel Ebner
-/
prelude
import Init.NotationExtra
namespace Lean
/--
The syntax category of binder predicates contains predicates like `> 0`, `∈ s`, etc.
(`: t` should not be a binder predicate because it would clash with the built-in syntax for ∀/∃.)
-/
declare_syntax_cat binderPred
/--
`satisfies_binder_pred% t pred` expands to a proposition expressing that `t` satisfies `pred`.
-/
syntax "satisfies_binder_pred% " term:max binderPred : term
-- Extend ∀ and ∃ to binder predicates.
/--
The notation `∃ x < 2, p x` is shorthand for `∃ x, x < 2 ∧ p x`,
and similarly for other binary operators.
-/
syntax "" binderIdent binderPred ", " term : term
/--
The notation `∀ x < 2, p x` is shorthand for `∀ x, x < 2 → p x`,
and similarly for other binary operators.
-/
syntax "" binderIdent binderPred ", " term : term
macro_rules
| `( $x:ident $pred:binderPred, $p) =>
`( $x:ident, satisfies_binder_pred% $x $pred $p)
| `( _ $pred:binderPred, $p) =>
`( x, satisfies_binder_pred% x $pred $p)
macro_rules
| `( $x:ident $pred:binderPred, $p) =>
`( $x:ident, satisfies_binder_pred% $x $pred $p)
| `( _ $pred:binderPred, $p) =>
`( x, satisfies_binder_pred% x $pred $p)
/-- Declare `∃ x > y, ...` as syntax for `∃ x, x > y ∧ ...` -/
binder_predicate x " > " y:term => `($x > $y)
/-- Declare `∃ x ≥ y, ...` as syntax for `∃ x, x ≥ y ∧ ...` -/
binder_predicate x "" y:term => `($x $y)
/-- Declare `∃ x < y, ...` as syntax for `∃ x, x < y ∧ ...` -/
binder_predicate x " < " y:term => `($x < $y)
/-- Declare `∃ x ≤ y, ...` as syntax for `∃ x, x ≤ y ∧ ...` -/
binder_predicate x "" y:term => `($x $y)
/-- Declare `∃ x ≠ y, ...` as syntax for `∃ x, x ≠ y ∧ ...` -/
binder_predicate x "" y:term => `($x $y)
/-- Declare `∀ x ∈ y, ...` as syntax for `∀ x, x ∈ y → ...` and `∃ x ∈ y, ...` as syntax for
`∃ x, x ∈ y ∧ ...` -/
binder_predicate x "" y:term => `($x $y)
/-- Declare `∀ x ∉ y, ...` as syntax for `∀ x, x ∉ y → ...` and `∃ x ∉ y, ...` as syntax for
`∃ x, x ∉ y ∧ ...` -/
binder_predicate x "" y:term => `($x $y)
/-- Declare `∀ x ⊆ y, ...` as syntax for `∀ x, x ⊆ y → ...` and `∃ x ⊆ y, ...` as syntax for
`∃ x, x ⊆ y ∧ ...` -/
binder_predicate x "" y:term => `($x $y)
/-- Declare `∀ x ⊂ y, ...` as syntax for `∀ x, x ⊂ y → ...` and `∃ x ⊂ y, ...` as syntax for
`∃ x, x ⊂ y ∧ ...` -/
binder_predicate x "" y:term => `($x $y)
/-- Declare `∀ x ⊇ y, ...` as syntax for `∀ x, x ⊇ y → ...` and `∃ x ⊇ y, ...` as syntax for
`∃ x, x ⊇ y ∧ ...` -/
binder_predicate x "" y:term => `($x $y)
/-- Declare `∀ x ⊃ y, ...` as syntax for `∀ x, x ⊃ y → ...` and `∃ x ⊃ y, ...` as syntax for
`∃ x, x ⊃ y ∧ ...` -/
binder_predicate x "" y:term => `($x $y)
end Lean

78
src/Init/ByCases.lean Normal file
View File

@@ -0,0 +1,78 @@
/-
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Mario Carneiro
-/
prelude
import Init.Classical
/-! # by_cases tactic and if-then-else support -/
/--
`by_cases (h :)? p` splits the main goal into two cases, assuming `h : p` in the first branch, and `h : ¬ p` in the second branch.
-/
syntax "by_cases " (atomic(ident " : "))? term : tactic
macro_rules
| `(tactic| by_cases $e) => `(tactic| by_cases h : $e)
macro_rules
| `(tactic| by_cases $h : $e) =>
`(tactic| open Classical in refine if $h:ident : $e then ?pos else ?neg)
/-! ## if-then-else -/
@[simp] theorem if_true {_ : Decidable True} (t e : α) : ite True t e = t := if_pos trivial
@[simp] theorem if_false {_ : Decidable False} (t e : α) : ite False t e = e := if_neg id
theorem ite_id [Decidable c] {α} (t : α) : (if c then t else t) = t := by split <;> rfl
/-- A function applied to a `dite` is a `dite` of that function applied to each of the branches. -/
theorem apply_dite (f : α β) (P : Prop) [Decidable P] (x : P α) (y : ¬P α) :
f (dite P x y) = dite P (fun h => f (x h)) (fun h => f (y h)) := by
by_cases h : P <;> simp [h]
/-- A function applied to a `ite` is a `ite` of that function applied to each of the branches. -/
theorem apply_ite (f : α β) (P : Prop) [Decidable P] (x y : α) :
f (ite P x y) = ite P (f x) (f y) :=
apply_dite f P (fun _ => x) (fun _ => y)
@[simp] theorem dite_eq_left_iff {P : Prop} [Decidable P] {B : ¬ P α} :
dite P (fun _ => a) B = a h, B h = a := by
by_cases P <;> simp [*, forall_prop_of_true, forall_prop_of_false]
@[simp] theorem dite_eq_right_iff {P : Prop} [Decidable P] {A : P α} :
(dite P A fun _ => b) = b h, A h = b := by
by_cases P <;> simp [*, forall_prop_of_true, forall_prop_of_false]
@[simp] theorem ite_eq_left_iff {P : Prop} [Decidable P] : ite P a b = a ¬P b = a :=
dite_eq_left_iff
@[simp] theorem ite_eq_right_iff {P : Prop} [Decidable P] : ite P a b = b P a = b :=
dite_eq_right_iff
/-- A `dite` whose results do not actually depend on the condition may be reduced to an `ite`. -/
@[simp] theorem dite_eq_ite [Decidable P] : (dite P (fun _ => a) fun _ => b) = ite P a b := rfl
-- We don't mark this as `simp` as it is already handled by `ite_eq_right_iff`.
theorem ite_some_none_eq_none [Decidable P] :
(if P then some x else none) = none ¬ P := by
simp only [ite_eq_right_iff]
rfl
@[simp] theorem ite_some_none_eq_some [Decidable P] :
(if P then some x else none) = some y P x = y := by
split <;> simp_all
-- This is not marked as `simp` as it is already handled by `dite_eq_right_iff`.
theorem dite_some_none_eq_none [Decidable P] {x : P α} :
(if h : P then some (x h) else none) = none ¬P := by
simp only [dite_eq_right_iff]
rfl
@[simp] theorem dite_some_none_eq_some [Decidable P] {x : P α} {y : α} :
(if h : P then some (x h) else none) = some y h : P, x h = y := by
by_cases h : P <;> simp only [h, dite_cond_eq_true, dite_cond_eq_false, Option.some.injEq,
false_iff, not_exists]
case pos => exact fun h_eq Exists.intro h h_eq, fun h_exists => h_exists.2
case neg => exact fun h_false _ h_false

View File

@@ -1,11 +1,10 @@
/-
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
Authors: Leonardo de Moura, Mario Carneiro
-/
prelude
import Init.Core
import Init.NotationExtra
import Init.PropLemmas
universe u v
@@ -16,6 +15,13 @@ namespace Classical
noncomputable def indefiniteDescription {α : Sort u} (p : α Prop) (h : x, p x) : {x // p x} :=
choice <| let x, px := h; x, px
/--
Given that there exists an element satisfying `p`, returns one such element.
This is a straightforward consequence of, and equivalent to, `Classical.choice`.
See also `choose_spec`, which asserts that the returned value has property `p`.
-/
noncomputable def choose {α : Sort u} {p : α Prop} (h : x, p x) : α :=
(indefiniteDescription p h).val
@@ -112,8 +118,8 @@ theorem skolem {α : Sort u} {b : α → Sort v} {p : ∀ x, b x → Prop} : (
theorem propComplete (a : Prop) : a = True a = False :=
match em a with
| Or.inl ha => Or.inl (propext (Iff.intro (fun _ => ) (fun _ => ha)))
| Or.inr hn => Or.inr (propext (Iff.intro (fun h => hn h) (fun h => False.elim h)))
| Or.inl ha => Or.inl (eq_true ha)
| Or.inr hn => Or.inr (eq_false hn)
-- this supercedes byCases in Decidable
theorem byCases {p q : Prop} (hpq : p q) (hnpq : ¬p q) : q :=
@@ -123,21 +129,49 @@ theorem byCases {p q : Prop} (hpq : p → q) (hnpq : ¬p → q) : q :=
theorem byContradiction {p : Prop} (h : ¬p False) : p :=
Decidable.byContradiction (dec := propDecidable _) h
/--
`by_cases (h :)? p` splits the main goal into two cases, assuming `h : p` in the first branch, and `h : ¬ p` in the second branch.
-/
syntax "by_cases " (atomic(ident " : "))? term : tactic
/-- The Double Negation Theorem: `¬¬P` is equivalent to `P`.
The left-to-right direction, double negation elimination (DNE),
is classically true but not constructively. -/
@[simp] theorem not_not : ¬¬a a := Decidable.not_not
macro_rules
| `(tactic| by_cases $h : $e) =>
`(tactic|
cases em $e with
| inl $h => _
| inr $h => _)
| `(tactic| by_cases $e) =>
`(tactic|
cases em $e with
| inl h => _
| inr h => _)
@[simp low] theorem not_forall {p : α Prop} : (¬ x, p x) x, ¬p x := Decidable.not_forall
theorem not_forall_not {p : α Prop} : (¬ x, ¬p x) x, p x := Decidable.not_forall_not
theorem not_exists_not {p : α Prop} : (¬ x, ¬p x) x, p x := Decidable.not_exists_not
theorem forall_or_exists_not (P : α Prop) : ( a, P a) a, ¬ P a := by
rw [ not_forall]; exact em _
theorem exists_or_forall_not (P : α Prop) : ( a, P a) a, ¬ P a := by
rw [ not_exists]; exact em _
theorem or_iff_not_imp_left : a b (¬a b) := Decidable.or_iff_not_imp_left
theorem or_iff_not_imp_right : a b (¬b a) := Decidable.or_iff_not_imp_right
theorem not_imp_iff_and_not : ¬(a b) a ¬b := Decidable.not_imp_iff_and_not
theorem not_and_iff_or_not_not : ¬(a b) ¬a ¬b := Decidable.not_and_iff_or_not_not
theorem not_iff : ¬(a b) (¬a b) := Decidable.not_iff
@[simp] theorem imp_iff_left_iff : (b a b) a b := Decidable.imp_iff_left_iff
@[simp] theorem imp_iff_right_iff : (a b b) a b := Decidable.imp_iff_right_iff
@[simp] theorem and_or_imp : a b (a c) a b c := Decidable.and_or_imp
@[simp] theorem not_imp : ¬(a b) a ¬b := Decidable.not_imp_iff_and_not
@[simp] theorem imp_and_neg_imp_iff (p q : Prop) : (p q) (¬p q) q :=
Iff.intro (fun (a : _ _) => (Classical.em p).rec a.left a.right)
(fun a => And.intro (fun _ => a) (fun _ => a))
end Classical
/- Export for Mathlib compat. -/
export Classical (imp_iff_right_iff imp_and_neg_imp_iff and_or_imp not_imp)
/-- Extract an element from a existential statement, using `Classical.choose`. -/
-- This enables projection notation.
@[reducible] noncomputable def Exists.choose {p : α Prop} (P : a, p a) : α := Classical.choose P
/-- Show that an element extracted from `P : ∃ a, p a` using `P.choose` satisfies `p`. -/
theorem Exists.choose_spec {p : α Prop} (P : a, p a) : p P.choose := Classical.choose_spec P

View File

@@ -290,6 +290,12 @@ between e.g. `↑x + ↑y` and `↑(x + y)`.
-/
syntax:1024 (name := coeNotation) "" term:1024 : term
/-- `⇑ t` coerces `t` to a function. -/
syntax:1024 (name := coeFunNotation) "" term:1024 : term
/-- `↥ t` coerces `t` to a type. -/
syntax:1024 (name := coeSortNotation) "" term:1024 : term
/-! # Basic instances -/
instance boolToProp : Coe Bool Prop where
@@ -315,7 +321,7 @@ Helper definition used by the elaborator. It is not meant to be used directly by
This is used for coercions between monads, in the case where we want to apply
a monad lift and a coercion on the result type at the same time.
-/
@[inline, coe_decl] def Lean.Internal.liftCoeM {m : Type u Type v} {n : Type u Type w} {α β : Type u}
@[coe_decl] abbrev Lean.Internal.liftCoeM {m : Type u Type v} {n : Type u Type w} {α β : Type u}
[MonadLiftT m n] [ a, CoeT α a β] [Monad n] (x : m α) : n β := do
let a liftM x
pure (CoeT.coe a)
@@ -325,7 +331,7 @@ Helper definition used by the elaborator. It is not meant to be used directly by
This is used for coercing the result type under a monad.
-/
@[inline, coe_decl] def Lean.Internal.coeM {m : Type u Type v} {α β : Type u}
@[coe_decl] abbrev Lean.Internal.coeM {m : Type u Type v} {α β : Type u}
[ a, CoeT α a β] [Monad m] (x : m α) : m β := do
let a x
pure (CoeT.coe a)

View File

@@ -20,8 +20,29 @@ def Functor.discard {f : Type u → Type v} {α : Type u} [Functor f] (x : f α)
export Functor (discard)
/--
An `Alternative` functor is an `Applicative` functor that can "fail" or be "empty"
and a binary operation `<|>` that “collects values” or finds the “left-most success”.
Important instances include
* `Option`, where `failure := none` and `<|>` returns the left-most `some`.
* Parser combinators typically provide an `Applicative` instance for error-handling and
backtracking.
Error recovery and state can interact subtly. For example, the implementation of `Alternative` for `OptionT (StateT σ Id)` keeps modifications made to the state while recovering from failure, while `StateT σ (OptionT Id)` discards them.
-/
-- NB: List instance is in mathlib. Once upstreamed, add
-- * `List`, where `failure` is the empty list and `<|>` concatenates.
class Alternative (f : Type u Type v) extends Applicative f : Type (max (u+1) v) where
/--
Produces an empty collection or recoverable failure. The `<|>` operator collects values or recovers
from failures. See `Alternative` for more details.
-/
failure : {α : Type u} f α
/--
Depending on the `Alternative` instance, collects values or recovers from `failure`s by
returning the leftmost success. Can be written using the `<|>` operator syntax.
-/
orElse : {α : Type u} f α (Unit f α) f α
instance (f : Type u Type v) (α : Type u) [Alternative f] : OrElse (f α) := Alternative.orElse
@@ -30,9 +51,15 @@ variable {f : Type u → Type v} [Alternative f] {α : Type u}
export Alternative (failure)
/--
If the proposition `p` is true, does nothing, else fails (using `failure`).
-/
@[always_inline, inline] def guard {f : Type Type v} [Alternative f] (p : Prop) [Decidable p] : f Unit :=
if p then pure () else failure
/--
Returns `some x` if `f` succeeds with value `x`, else returns `none`.
-/
@[always_inline, inline] def optional (x : f α) : f (Option α) :=
some <$> x <|> pure none

View File

@@ -131,7 +131,7 @@ protected def adapt {ε' α : Type u} (f : ε → ε') : ExceptT ε m α → Exc
end ExceptT
@[always_inline]
instance (m : Type u Type v) (ε₁ : Type u) (ε₂ : Type u) [Monad m] [MonadExceptOf ε₁ m] : MonadExceptOf ε₁ (ExceptT ε₂ m) where
instance (m : Type u Type v) (ε₁ : Type u) (ε₂ : Type u) [MonadExceptOf ε₁ m] : MonadExceptOf ε₁ (ExceptT ε₂ m) where
throw e := ExceptT.mk <| throwThe ε₁ e
tryCatch x handle := ExceptT.mk <| tryCatchThe ε₁ x handle

View File

@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.Control.Lawful
import Init.Control.Lawful.Basic
/-!
The Exception monad transformer using CPS style.
@@ -18,6 +18,7 @@ namespace ExceptCpsT
def run {ε α : Type u} [Monad m] (x : ExceptCpsT ε m α) : m (Except ε α) :=
x _ (fun a => pure (Except.ok a)) (fun e => pure (Except.error e))
set_option linter.unusedVariables false in -- `s` unused
@[always_inline, inline]
def runK {ε α : Type u} (x : ExceptCpsT ε m α) (s : ε) (ok : α m β) (error : ε m β) : m β :=
x _ ok error

View File

@@ -1,309 +1,8 @@
/-
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sebastian Ullrich, Leonardo de Moura
Authors: Sebastian Ullrich, Leonardo de Moura, Mario Carneiro
-/
prelude
import Init.SimpLemmas
import Init.Control.Except
import Init.Control.StateRef
open Function
@[simp] theorem monadLift_self [Monad m] (x : m α) : monadLift x = x :=
rfl
class LawfulFunctor (f : Type u Type v) [Functor f] : Prop where
map_const : (Functor.mapConst : α f β f α) = Functor.map const β
id_map (x : f α) : id <$> x = x
comp_map (g : α β) (h : β γ) (x : f α) : (h g) <$> x = h <$> g <$> x
export LawfulFunctor (map_const id_map comp_map)
attribute [simp] id_map
@[simp] theorem id_map' [Functor m] [LawfulFunctor m] (x : m α) : (fun a => a) <$> x = x :=
id_map x
class LawfulApplicative (f : Type u Type v) [Applicative f] extends LawfulFunctor f : Prop where
seqLeft_eq (x : f α) (y : f β) : x <* y = const β <$> x <*> y
seqRight_eq (x : f α) (y : f β) : x *> y = const α id <$> x <*> y
pure_seq (g : α β) (x : f α) : pure g <*> x = g <$> x
map_pure (g : α β) (x : α) : g <$> (pure x : f α) = pure (g x)
seq_pure {α β : Type u} (g : f (α β)) (x : α) : g <*> pure x = (fun h => h x) <$> g
seq_assoc {α β γ : Type u} (x : f α) (g : f (α β)) (h : f (β γ)) : h <*> (g <*> x) = ((@comp α β γ) <$> h) <*> g <*> x
comp_map g h x := (by
repeat rw [ pure_seq]
simp [seq_assoc, map_pure, seq_pure])
export LawfulApplicative (seqLeft_eq seqRight_eq pure_seq map_pure seq_pure seq_assoc)
attribute [simp] map_pure seq_pure
@[simp] theorem pure_id_seq [Applicative f] [LawfulApplicative f] (x : f α) : pure id <*> x = x := by
simp [pure_seq]
class LawfulMonad (m : Type u Type v) [Monad m] extends LawfulApplicative m : Prop where
bind_pure_comp (f : α β) (x : m α) : x >>= (fun a => pure (f a)) = f <$> x
bind_map {α β : Type u} (f : m (α β)) (x : m α) : f >>= (. <$> x) = f <*> x
pure_bind (x : α) (f : α m β) : pure x >>= f = f x
bind_assoc (x : m α) (f : α m β) (g : β m γ) : x >>= f >>= g = x >>= fun x => f x >>= g
map_pure g x := (by rw [ bind_pure_comp, pure_bind])
seq_pure g x := (by rw [ bind_map]; simp [map_pure, bind_pure_comp])
seq_assoc x g h := (by simp [ bind_pure_comp, bind_map, bind_assoc, pure_bind])
export LawfulMonad (bind_pure_comp bind_map pure_bind bind_assoc)
attribute [simp] pure_bind bind_assoc
@[simp] theorem bind_pure [Monad m] [LawfulMonad m] (x : m α) : x >>= pure = x := by
show x >>= (fun a => pure (id a)) = x
rw [bind_pure_comp, id_map]
theorem map_eq_pure_bind [Monad m] [LawfulMonad m] (f : α β) (x : m α) : f <$> x = x >>= fun a => pure (f a) := by
rw [ bind_pure_comp]
theorem seq_eq_bind_map {α β : Type u} [Monad m] [LawfulMonad m] (f : m (α β)) (x : m α) : f <*> x = f >>= (. <$> x) := by
rw [ bind_map]
theorem bind_congr [Bind m] {x : m α} {f g : α m β} (h : a, f a = g a) : x >>= f = x >>= g := by
simp [funext h]
@[simp] theorem bind_pure_unit [Monad m] [LawfulMonad m] {x : m PUnit} : (x >>= fun _ => pure ) = x := by
rw [bind_pure]
theorem map_congr [Functor m] {x : m α} {f g : α β} (h : a, f a = g a) : (f <$> x : m β) = g <$> x := by
simp [funext h]
theorem seq_eq_bind {α β : Type u} [Monad m] [LawfulMonad m] (mf : m (α β)) (x : m α) : mf <*> x = mf >>= fun f => f <$> x := by
rw [bind_map]
theorem seqRight_eq_bind [Monad m] [LawfulMonad m] (x : m α) (y : m β) : x *> y = x >>= fun _ => y := by
rw [seqRight_eq]
simp [map_eq_pure_bind, seq_eq_bind_map, const]
theorem seqLeft_eq_bind [Monad m] [LawfulMonad m] (x : m α) (y : m β) : x <* y = x >>= fun a => y >>= fun _ => pure a := by
rw [seqLeft_eq]; simp [map_eq_pure_bind, seq_eq_bind_map]
/-! # Id -/
namespace Id
@[simp] theorem map_eq (x : Id α) (f : α β) : f <$> x = f x := rfl
@[simp] theorem bind_eq (x : Id α) (f : α id β) : x >>= f = f x := rfl
@[simp] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
instance : LawfulMonad Id := by
refine' { .. } <;> intros <;> rfl
end Id
/-! # ExceptT -/
namespace ExceptT
theorem ext [Monad m] {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
simp [run] at h
assumption
@[simp] theorem run_pure [Monad m] (x : α) : run (pure x : ExceptT ε m α) = pure (Except.ok x) := rfl
@[simp] theorem run_lift [Monad.{u, v} m] (x : m α) : run (ExceptT.lift x : ExceptT ε m α) = (Except.ok <$> x : m (Except ε α)) := rfl
@[simp] theorem run_throw [Monad m] : run (throw e : ExceptT ε m β) = pure (Except.error e) := rfl
@[simp] theorem run_bind_lift [Monad m] [LawfulMonad m] (x : m α) (f : α ExceptT ε m β) : run (ExceptT.lift x >>= f : ExceptT ε m β) = x >>= fun a => run (f a) := by
simp[ExceptT.run, ExceptT.lift, bind, ExceptT.bind, ExceptT.mk, ExceptT.bindCont, map_eq_pure_bind]
@[simp] theorem bind_throw [Monad m] [LawfulMonad m] (f : α ExceptT ε m β) : (throw e >>= f) = throw e := by
simp [throw, throwThe, MonadExceptOf.throw, bind, ExceptT.bind, ExceptT.bindCont, ExceptT.mk]
theorem run_bind [Monad m] (x : ExceptT ε m α)
: run (x >>= f : ExceptT ε m β)
=
run x >>= fun
| Except.ok x => run (f x)
| Except.error e => pure (Except.error e) :=
rfl
@[simp] theorem lift_pure [Monad m] [LawfulMonad m] (a : α) : ExceptT.lift (pure a) = (pure a : ExceptT ε m α) := by
simp [ExceptT.lift, pure, ExceptT.pure]
@[simp] theorem run_map [Monad m] [LawfulMonad m] (f : α β) (x : ExceptT ε m α)
: (f <$> x).run = Except.map f <$> x.run := by
simp [Functor.map, ExceptT.map, map_eq_pure_bind]
apply bind_congr
intro a; cases a <;> simp [Except.map]
protected theorem seq_eq {α β ε : Type u} [Monad m] (mf : ExceptT ε m (α β)) (x : ExceptT ε m α) : mf <*> x = mf >>= fun f => f <$> x :=
rfl
protected theorem bind_pure_comp [Monad m] [LawfulMonad m] (f : α β) (x : ExceptT ε m α) : x >>= pure f = f <$> x := by
intros; rfl
protected theorem seqLeft_eq {α β ε : Type u} {m : Type u Type v} [Monad m] [LawfulMonad m] (x : ExceptT ε m α) (y : ExceptT ε m β) : x <* y = const β <$> x <*> y := by
show (x >>= fun a => y >>= fun _ => pure a) = (const (α := α) β <$> x) >>= fun f => f <$> y
rw [ ExceptT.bind_pure_comp]
apply ext
simp [run_bind]
apply bind_congr
intro
| Except.error _ => simp
| Except.ok _ =>
simp [map_eq_pure_bind]; apply bind_congr; intro b;
cases b <;> simp [comp, Except.map, const]
protected theorem seqRight_eq [Monad m] [LawfulMonad m] (x : ExceptT ε m α) (y : ExceptT ε m β) : x *> y = const α id <$> x <*> y := by
show (x >>= fun _ => y) = (const α id <$> x) >>= fun f => f <$> y
rw [ ExceptT.bind_pure_comp]
apply ext
simp [run_bind]
apply bind_congr
intro a; cases a <;> simp
instance [Monad m] [LawfulMonad m] : LawfulMonad (ExceptT ε m) where
id_map := by intros; apply ext; simp
map_const := by intros; rfl
seqLeft_eq := ExceptT.seqLeft_eq
seqRight_eq := ExceptT.seqRight_eq
pure_seq := by intros; apply ext; simp [ExceptT.seq_eq, run_bind]
bind_pure_comp := ExceptT.bind_pure_comp
bind_map := by intros; rfl
pure_bind := by intros; apply ext; simp [run_bind]
bind_assoc := by intros; apply ext; simp [run_bind]; apply bind_congr; intro a; cases a <;> simp
end ExceptT
/-! # ReaderT -/
namespace ReaderT
theorem ext {x y : ReaderT ρ m α} (h : ctx, x.run ctx = y.run ctx) : x = y := by
simp [run] at h
exact funext h
@[simp] theorem run_pure [Monad m] (a : α) (ctx : ρ) : (pure a : ReaderT ρ m α).run ctx = pure a := rfl
@[simp] theorem run_bind [Monad m] (x : ReaderT ρ m α) (f : α ReaderT ρ m β) (ctx : ρ)
: (x >>= f).run ctx = x.run ctx >>= λ a => (f a).run ctx := rfl
@[simp] theorem run_mapConst [Monad m] (a : α) (x : ReaderT ρ m β) (ctx : ρ)
: (Functor.mapConst a x).run ctx = Functor.mapConst a (x.run ctx) := rfl
@[simp] theorem run_map [Monad m] (f : α β) (x : ReaderT ρ m α) (ctx : ρ)
: (f <$> x).run ctx = f <$> x.run ctx := rfl
@[simp] theorem run_monadLift [MonadLiftT n m] (x : n α) (ctx : ρ)
: (monadLift x : ReaderT ρ m α).run ctx = (monadLift x : m α) := rfl
@[simp] theorem run_monadMap [MonadFunctor n m] (f : {β : Type u} n β n β) (x : ReaderT ρ m α) (ctx : ρ)
: (monadMap @f x : ReaderT ρ m α).run ctx = monadMap @f (x.run ctx) := rfl
@[simp] theorem run_read [Monad m] (ctx : ρ) : (ReaderT.read : ReaderT ρ m ρ).run ctx = pure ctx := rfl
@[simp] theorem run_seq {α β : Type u} [Monad m] (f : ReaderT ρ m (α β)) (x : ReaderT ρ m α) (ctx : ρ)
: (f <*> x).run ctx = (f.run ctx <*> x.run ctx) := rfl
@[simp] theorem run_seqRight [Monad m] (x : ReaderT ρ m α) (y : ReaderT ρ m β) (ctx : ρ)
: (x *> y).run ctx = (x.run ctx *> y.run ctx) := rfl
@[simp] theorem run_seqLeft [Monad m] (x : ReaderT ρ m α) (y : ReaderT ρ m β) (ctx : ρ)
: (x <* y).run ctx = (x.run ctx <* y.run ctx) := rfl
instance [Monad m] [LawfulFunctor m] : LawfulFunctor (ReaderT ρ m) where
id_map := by intros; apply ext; simp
map_const := by intros; funext a b; apply ext; intros; simp [map_const]
comp_map := by intros; apply ext; intros; simp [comp_map]
instance [Monad m] [LawfulApplicative m] : LawfulApplicative (ReaderT ρ m) where
seqLeft_eq := by intros; apply ext; intros; simp [seqLeft_eq]
seqRight_eq := by intros; apply ext; intros; simp [seqRight_eq]
pure_seq := by intros; apply ext; intros; simp [pure_seq]
map_pure := by intros; apply ext; intros; simp [map_pure]
seq_pure := by intros; apply ext; intros; simp [seq_pure]
seq_assoc := by intros; apply ext; intros; simp [seq_assoc]
instance [Monad m] [LawfulMonad m] : LawfulMonad (ReaderT ρ m) where
bind_pure_comp := by intros; apply ext; intros; simp [LawfulMonad.bind_pure_comp]
bind_map := by intros; apply ext; intros; simp [bind_map]
pure_bind := by intros; apply ext; intros; simp
bind_assoc := by intros; apply ext; intros; simp
end ReaderT
/-! # StateRefT -/
instance [Monad m] [LawfulMonad m] : LawfulMonad (StateRefT' ω σ m) :=
inferInstanceAs (LawfulMonad (ReaderT (ST.Ref ω σ) m))
/-! # StateT -/
namespace StateT
theorem ext {x y : StateT σ m α} (h : s, x.run s = y.run s) : x = y :=
funext h
@[simp] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=
rfl
@[simp] theorem run_pure [Monad m] (a : α) (s : σ) : (pure a : StateT σ m α).run s = pure (a, s) := rfl
@[simp] theorem run_bind [Monad m] (x : StateT σ m α) (f : α StateT σ m β) (s : σ)
: (x >>= f).run s = x.run s >>= λ p => (f p.1).run p.2 := by
simp [bind, StateT.bind, run]
@[simp] theorem run_map {α β σ : Type u} [Monad m] [LawfulMonad m] (f : α β) (x : StateT σ m α) (s : σ) : (f <$> x).run s = (fun (p : α × σ) => (f p.1, p.2)) <$> x.run s := by
simp [Functor.map, StateT.map, run, map_eq_pure_bind]
@[simp] theorem run_get [Monad m] (s : σ) : (get : StateT σ m σ).run s = pure (s, s) := rfl
@[simp] theorem run_set [Monad m] (s s' : σ) : (set s' : StateT σ m PUnit).run s = pure (, s') := rfl
@[simp] theorem run_modify [Monad m] (f : σ σ) (s : σ) : (modify f : StateT σ m PUnit).run s = pure (, f s) := rfl
@[simp] theorem run_modifyGet [Monad m] (f : σ α × σ) (s : σ) : (modifyGet f : StateT σ m α).run s = pure ((f s).1, (f s).2) := by
simp [modifyGet, MonadStateOf.modifyGet, StateT.modifyGet, run]
@[simp] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
@[simp] theorem run_bind_lift {α σ : Type u} [Monad m] [LawfulMonad m] (x : m α) (f : α StateT σ m β) (s : σ) : (StateT.lift x >>= f).run s = x >>= fun a => (f a).run s := by
simp [StateT.lift, StateT.run, bind, StateT.bind]
@[simp] theorem run_monadLift {α σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) : (monadLift x : StateT σ m α).run s = (monadLift x : m α) >>= fun a => pure (a, s) := rfl
@[simp] theorem run_monadMap [Monad m] [MonadFunctor n m] (f : {β : Type u} n β n β) (x : StateT σ m α) (s : σ)
: (monadMap @f x : StateT σ m α).run s = monadMap @f (x.run s) := rfl
@[simp] theorem run_seq {α β σ : Type u} [Monad m] [LawfulMonad m] (f : StateT σ m (α β)) (x : StateT σ m α) (s : σ) : (f <*> x).run s = (f.run s >>= fun fs => (fun (p : α × σ) => (fs.1 p.1, p.2)) <$> x.run fs.2) := by
show (f >>= fun g => g <$> x).run s = _
simp
@[simp] theorem run_seqRight [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x *> y).run s = (x.run s >>= fun p => y.run p.2) := by
show (x >>= fun _ => y).run s = _
simp
@[simp] theorem run_seqLeft {α β σ : Type u} [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x <* y).run s = (x.run s >>= fun p => y.run p.2 >>= fun p' => pure (p.1, p'.2)) := by
show (x >>= fun a => y >>= fun _ => pure a).run s = _
simp
theorem seqRight_eq [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) : x *> y = const α id <$> x <*> y := by
apply ext; intro s
simp [map_eq_pure_bind, const]
apply bind_congr; intro p; cases p
simp [Prod.eta]
theorem seqLeft_eq [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) : x <* y = const β <$> x <*> y := by
apply ext; intro s
simp [map_eq_pure_bind]
instance [Monad m] [LawfulMonad m] : LawfulMonad (StateT σ m) where
id_map := by intros; apply ext; intros; simp[Prod.eta]
map_const := by intros; rfl
seqLeft_eq := seqLeft_eq
seqRight_eq := seqRight_eq
pure_seq := by intros; apply ext; intros; simp
bind_pure_comp := by intros; apply ext; intros; simp; apply LawfulMonad.bind_pure_comp
bind_map := by intros; rfl
pure_bind := by intros; apply ext; intros; simp
bind_assoc := by intros; apply ext; intros; simp
end StateT
import Init.Control.Lawful.Basic
import Init.Control.Lawful.Instances

View File

@@ -0,0 +1,169 @@
/-
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sebastian Ullrich, Leonardo de Moura, Mario Carneiro
-/
prelude
import Init.SimpLemmas
import Init.Meta
open Function
@[simp] theorem monadLift_self {m : Type u Type v} (x : m α) : monadLift x = x :=
rfl
/--
The `Functor` typeclass only contains the operations of a functor.
`LawfulFunctor` further asserts that these operations satisfy the laws of a functor,
including the preservation of the identity and composition laws:
```
id <$> x = x
(h ∘ g) <$> x = h <$> g <$> x
```
-/
class LawfulFunctor (f : Type u Type v) [Functor f] : Prop where
map_const : (Functor.mapConst : α f β f α) = Functor.map const β
id_map (x : f α) : id <$> x = x
comp_map (g : α β) (h : β γ) (x : f α) : (h g) <$> x = h <$> g <$> x
export LawfulFunctor (map_const id_map comp_map)
attribute [simp] id_map
@[simp] theorem id_map' [Functor m] [LawfulFunctor m] (x : m α) : (fun a => a) <$> x = x :=
id_map x
/--
The `Applicative` typeclass only contains the operations of an applicative functor.
`LawfulApplicative` further asserts that these operations satisfy the laws of an applicative functor:
```
pure id <*> v = v
pure (·∘·) <*> u <*> v <*> w = u <*> (v <*> w)
pure f <*> pure x = pure (f x)
u <*> pure y = pure (· y) <*> u
```
-/
class LawfulApplicative (f : Type u Type v) [Applicative f] extends LawfulFunctor f : Prop where
seqLeft_eq (x : f α) (y : f β) : x <* y = const β <$> x <*> y
seqRight_eq (x : f α) (y : f β) : x *> y = const α id <$> x <*> y
pure_seq (g : α β) (x : f α) : pure g <*> x = g <$> x
map_pure (g : α β) (x : α) : g <$> (pure x : f α) = pure (g x)
seq_pure {α β : Type u} (g : f (α β)) (x : α) : g <*> pure x = (fun h => h x) <$> g
seq_assoc {α β γ : Type u} (x : f α) (g : f (α β)) (h : f (β γ)) : h <*> (g <*> x) = ((@comp α β γ) <$> h) <*> g <*> x
comp_map g h x := (by
repeat rw [ pure_seq]
simp [seq_assoc, map_pure, seq_pure])
export LawfulApplicative (seqLeft_eq seqRight_eq pure_seq map_pure seq_pure seq_assoc)
attribute [simp] map_pure seq_pure
@[simp] theorem pure_id_seq [Applicative f] [LawfulApplicative f] (x : f α) : pure id <*> x = x := by
simp [pure_seq]
/--
The `Monad` typeclass only contains the operations of a monad.
`LawfulMonad` further asserts that these operations satisfy the laws of a monad,
including associativity and identity laws for `bind`:
```
pure x >>= f = f x
x >>= pure = x
x >>= f >>= g = x >>= (fun x => f x >>= g)
```
`LawfulMonad.mk'` is an alternative constructor containing useful defaults for many fields.
-/
class LawfulMonad (m : Type u Type v) [Monad m] extends LawfulApplicative m : Prop where
bind_pure_comp (f : α β) (x : m α) : x >>= (fun a => pure (f a)) = f <$> x
bind_map {α β : Type u} (f : m (α β)) (x : m α) : f >>= (. <$> x) = f <*> x
pure_bind (x : α) (f : α m β) : pure x >>= f = f x
bind_assoc (x : m α) (f : α m β) (g : β m γ) : x >>= f >>= g = x >>= fun x => f x >>= g
map_pure g x := (by rw [ bind_pure_comp, pure_bind])
seq_pure g x := (by rw [ bind_map]; simp [map_pure, bind_pure_comp])
seq_assoc x g h := (by simp [ bind_pure_comp, bind_map, bind_assoc, pure_bind])
export LawfulMonad (bind_pure_comp bind_map pure_bind bind_assoc)
attribute [simp] pure_bind bind_assoc
@[simp] theorem bind_pure [Monad m] [LawfulMonad m] (x : m α) : x >>= pure = x := by
show x >>= (fun a => pure (id a)) = x
rw [bind_pure_comp, id_map]
theorem map_eq_pure_bind [Monad m] [LawfulMonad m] (f : α β) (x : m α) : f <$> x = x >>= fun a => pure (f a) := by
rw [ bind_pure_comp]
theorem seq_eq_bind_map {α β : Type u} [Monad m] [LawfulMonad m] (f : m (α β)) (x : m α) : f <*> x = f >>= (. <$> x) := by
rw [ bind_map]
theorem bind_congr [Bind m] {x : m α} {f g : α m β} (h : a, f a = g a) : x >>= f = x >>= g := by
simp [funext h]
@[simp] theorem bind_pure_unit [Monad m] [LawfulMonad m] {x : m PUnit} : (x >>= fun _ => pure ) = x := by
rw [bind_pure]
theorem map_congr [Functor m] {x : m α} {f g : α β} (h : a, f a = g a) : (f <$> x : m β) = g <$> x := by
simp [funext h]
theorem seq_eq_bind {α β : Type u} [Monad m] [LawfulMonad m] (mf : m (α β)) (x : m α) : mf <*> x = mf >>= fun f => f <$> x := by
rw [bind_map]
theorem seqRight_eq_bind [Monad m] [LawfulMonad m] (x : m α) (y : m β) : x *> y = x >>= fun _ => y := by
rw [seqRight_eq]
simp [map_eq_pure_bind, seq_eq_bind_map, const]
theorem seqLeft_eq_bind [Monad m] [LawfulMonad m] (x : m α) (y : m β) : x <* y = x >>= fun a => y >>= fun _ => pure a := by
rw [seqLeft_eq]; simp [map_eq_pure_bind, seq_eq_bind_map]
/--
An alternative constructor for `LawfulMonad` which has more
defaultable fields in the common case.
-/
theorem LawfulMonad.mk' (m : Type u Type v) [Monad m]
(id_map : {α} (x : m α), id <$> x = x)
(pure_bind : {α β} (x : α) (f : α m β), pure x >>= f = f x)
(bind_assoc : {α β γ} (x : m α) (f : α m β) (g : β m γ),
x >>= f >>= g = x >>= fun x => f x >>= g)
(map_const : {α β} (x : α) (y : m β),
Functor.mapConst x y = Function.const β x <$> y := by intros; rfl)
(seqLeft_eq : {α β} (x : m α) (y : m β),
x <* y = (x >>= fun a => y >>= fun _ => pure a) := by intros; rfl)
(seqRight_eq : {α β} (x : m α) (y : m β), x *> y = (x >>= fun _ => y) := by intros; rfl)
(bind_pure_comp : {α β} (f : α β) (x : m α),
x >>= (fun y => pure (f y)) = f <$> x := by intros; rfl)
(bind_map : {α β} (f : m (α β)) (x : m α), f >>= (. <$> x) = f <*> x := by intros; rfl)
: LawfulMonad m :=
have map_pure {α β} (g : α β) (x : α) : g <$> (pure x : m α) = pure (g x) := by
rw [ bind_pure_comp]; simp [pure_bind]
{ id_map, bind_pure_comp, bind_map, pure_bind, bind_assoc, map_pure,
comp_map := by simp [ bind_pure_comp, bind_assoc, pure_bind]
pure_seq := by intros; rw [ bind_map]; simp [pure_bind]
seq_pure := by intros; rw [ bind_map]; simp [map_pure, bind_pure_comp]
seq_assoc := by simp [ bind_pure_comp, bind_map, bind_assoc, pure_bind]
map_const := funext fun x => funext (map_const x)
seqLeft_eq := by simp [seqLeft_eq, bind_map, bind_pure_comp, pure_bind, bind_assoc]
seqRight_eq := fun x y => by
rw [seqRight_eq, bind_map, bind_pure_comp, bind_assoc]; simp [pure_bind, id_map] }
/-! # Id -/
namespace Id
@[simp] theorem map_eq (x : Id α) (f : α β) : f <$> x = f x := rfl
@[simp] theorem bind_eq (x : Id α) (f : α id β) : x >>= f = f x := rfl
@[simp] theorem pure_eq (a : α) : (pure a : Id α) = a := rfl
instance : LawfulMonad Id := by
refine' { .. } <;> intros <;> rfl
end Id
/-! # Option -/
instance : LawfulMonad Option := LawfulMonad.mk'
(id_map := fun x => by cases x <;> rfl)
(pure_bind := fun x f => rfl)
(bind_assoc := fun x f g => by cases x <;> rfl)
(bind_pure_comp := fun f x => by cases x <;> rfl)
instance : LawfulApplicative Option := inferInstance
instance : LawfulFunctor Option := inferInstance

View File

@@ -0,0 +1,248 @@
/-
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Sebastian Ullrich, Leonardo de Moura, Mario Carneiro
-/
prelude
import Init.Control.Lawful.Basic
import Init.Control.Except
import Init.Control.StateRef
open Function
/-! # ExceptT -/
namespace ExceptT
theorem ext {x y : ExceptT ε m α} (h : x.run = y.run) : x = y := by
simp [run] at h
assumption
@[simp] theorem run_pure [Monad m] (x : α) : run (pure x : ExceptT ε m α) = pure (Except.ok x) := rfl
@[simp] theorem run_lift [Monad.{u, v} m] (x : m α) : run (ExceptT.lift x : ExceptT ε m α) = (Except.ok <$> x : m (Except ε α)) := rfl
@[simp] theorem run_throw [Monad m] : run (throw e : ExceptT ε m β) = pure (Except.error e) := rfl
@[simp] theorem run_bind_lift [Monad m] [LawfulMonad m] (x : m α) (f : α ExceptT ε m β) : run (ExceptT.lift x >>= f : ExceptT ε m β) = x >>= fun a => run (f a) := by
simp[ExceptT.run, ExceptT.lift, bind, ExceptT.bind, ExceptT.mk, ExceptT.bindCont, map_eq_pure_bind]
@[simp] theorem bind_throw [Monad m] [LawfulMonad m] (f : α ExceptT ε m β) : (throw e >>= f) = throw e := by
simp [throw, throwThe, MonadExceptOf.throw, bind, ExceptT.bind, ExceptT.bindCont, ExceptT.mk]
theorem run_bind [Monad m] (x : ExceptT ε m α)
: run (x >>= f : ExceptT ε m β)
=
run x >>= fun
| Except.ok x => run (f x)
| Except.error e => pure (Except.error e) :=
rfl
@[simp] theorem lift_pure [Monad m] [LawfulMonad m] (a : α) : ExceptT.lift (pure a) = (pure a : ExceptT ε m α) := by
simp [ExceptT.lift, pure, ExceptT.pure]
@[simp] theorem run_map [Monad m] [LawfulMonad m] (f : α β) (x : ExceptT ε m α)
: (f <$> x).run = Except.map f <$> x.run := by
simp [Functor.map, ExceptT.map, map_eq_pure_bind]
apply bind_congr
intro a; cases a <;> simp [Except.map]
protected theorem seq_eq {α β ε : Type u} [Monad m] (mf : ExceptT ε m (α β)) (x : ExceptT ε m α) : mf <*> x = mf >>= fun f => f <$> x :=
rfl
protected theorem bind_pure_comp [Monad m] (f : α β) (x : ExceptT ε m α) : x >>= pure f = f <$> x := by
intros; rfl
protected theorem seqLeft_eq {α β ε : Type u} {m : Type u Type v} [Monad m] [LawfulMonad m] (x : ExceptT ε m α) (y : ExceptT ε m β) : x <* y = const β <$> x <*> y := by
show (x >>= fun a => y >>= fun _ => pure a) = (const (α := α) β <$> x) >>= fun f => f <$> y
rw [ ExceptT.bind_pure_comp]
apply ext
simp [run_bind]
apply bind_congr
intro
| Except.error _ => simp
| Except.ok _ =>
simp [map_eq_pure_bind]; apply bind_congr; intro b;
cases b <;> simp [comp, Except.map, const]
protected theorem seqRight_eq [Monad m] [LawfulMonad m] (x : ExceptT ε m α) (y : ExceptT ε m β) : x *> y = const α id <$> x <*> y := by
show (x >>= fun _ => y) = (const α id <$> x) >>= fun f => f <$> y
rw [ ExceptT.bind_pure_comp]
apply ext
simp [run_bind]
apply bind_congr
intro a; cases a <;> simp
instance [Monad m] [LawfulMonad m] : LawfulMonad (ExceptT ε m) where
id_map := by intros; apply ext; simp
map_const := by intros; rfl
seqLeft_eq := ExceptT.seqLeft_eq
seqRight_eq := ExceptT.seqRight_eq
pure_seq := by intros; apply ext; simp [ExceptT.seq_eq, run_bind]
bind_pure_comp := ExceptT.bind_pure_comp
bind_map := by intros; rfl
pure_bind := by intros; apply ext; simp [run_bind]
bind_assoc := by intros; apply ext; simp [run_bind]; apply bind_congr; intro a; cases a <;> simp
end ExceptT
/-! # Except -/
instance : LawfulMonad (Except ε) := LawfulMonad.mk'
(id_map := fun x => by cases x <;> rfl)
(pure_bind := fun a f => rfl)
(bind_assoc := fun a f g => by cases a <;> rfl)
instance : LawfulApplicative (Except ε) := inferInstance
instance : LawfulFunctor (Except ε) := inferInstance
/-! # ReaderT -/
namespace ReaderT
theorem ext {x y : ReaderT ρ m α} (h : ctx, x.run ctx = y.run ctx) : x = y := by
simp [run] at h
exact funext h
@[simp] theorem run_pure [Monad m] (a : α) (ctx : ρ) : (pure a : ReaderT ρ m α).run ctx = pure a := rfl
@[simp] theorem run_bind [Monad m] (x : ReaderT ρ m α) (f : α ReaderT ρ m β) (ctx : ρ)
: (x >>= f).run ctx = x.run ctx >>= λ a => (f a).run ctx := rfl
@[simp] theorem run_mapConst [Monad m] (a : α) (x : ReaderT ρ m β) (ctx : ρ)
: (Functor.mapConst a x).run ctx = Functor.mapConst a (x.run ctx) := rfl
@[simp] theorem run_map [Monad m] (f : α β) (x : ReaderT ρ m α) (ctx : ρ)
: (f <$> x).run ctx = f <$> x.run ctx := rfl
@[simp] theorem run_monadLift [MonadLiftT n m] (x : n α) (ctx : ρ)
: (monadLift x : ReaderT ρ m α).run ctx = (monadLift x : m α) := rfl
@[simp] theorem run_monadMap [MonadFunctor n m] (f : {β : Type u} n β n β) (x : ReaderT ρ m α) (ctx : ρ)
: (monadMap @f x : ReaderT ρ m α).run ctx = monadMap @f (x.run ctx) := rfl
@[simp] theorem run_read [Monad m] (ctx : ρ) : (ReaderT.read : ReaderT ρ m ρ).run ctx = pure ctx := rfl
@[simp] theorem run_seq {α β : Type u} [Monad m] (f : ReaderT ρ m (α β)) (x : ReaderT ρ m α) (ctx : ρ)
: (f <*> x).run ctx = (f.run ctx <*> x.run ctx) := rfl
@[simp] theorem run_seqRight [Monad m] (x : ReaderT ρ m α) (y : ReaderT ρ m β) (ctx : ρ)
: (x *> y).run ctx = (x.run ctx *> y.run ctx) := rfl
@[simp] theorem run_seqLeft [Monad m] (x : ReaderT ρ m α) (y : ReaderT ρ m β) (ctx : ρ)
: (x <* y).run ctx = (x.run ctx <* y.run ctx) := rfl
instance [Monad m] [LawfulFunctor m] : LawfulFunctor (ReaderT ρ m) where
id_map := by intros; apply ext; simp
map_const := by intros; funext a b; apply ext; intros; simp [map_const]
comp_map := by intros; apply ext; intros; simp [comp_map]
instance [Monad m] [LawfulApplicative m] : LawfulApplicative (ReaderT ρ m) where
seqLeft_eq := by intros; apply ext; intros; simp [seqLeft_eq]
seqRight_eq := by intros; apply ext; intros; simp [seqRight_eq]
pure_seq := by intros; apply ext; intros; simp [pure_seq]
map_pure := by intros; apply ext; intros; simp [map_pure]
seq_pure := by intros; apply ext; intros; simp [seq_pure]
seq_assoc := by intros; apply ext; intros; simp [seq_assoc]
instance [Monad m] [LawfulMonad m] : LawfulMonad (ReaderT ρ m) where
bind_pure_comp := by intros; apply ext; intros; simp [LawfulMonad.bind_pure_comp]
bind_map := by intros; apply ext; intros; simp [bind_map]
pure_bind := by intros; apply ext; intros; simp
bind_assoc := by intros; apply ext; intros; simp
end ReaderT
/-! # StateRefT -/
instance [Monad m] [LawfulMonad m] : LawfulMonad (StateRefT' ω σ m) :=
inferInstanceAs (LawfulMonad (ReaderT (ST.Ref ω σ) m))
/-! # StateT -/
namespace StateT
theorem ext {x y : StateT σ m α} (h : s, x.run s = y.run s) : x = y :=
funext h
@[simp] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=
rfl
@[simp] theorem run_pure [Monad m] (a : α) (s : σ) : (pure a : StateT σ m α).run s = pure (a, s) := rfl
@[simp] theorem run_bind [Monad m] (x : StateT σ m α) (f : α StateT σ m β) (s : σ)
: (x >>= f).run s = x.run s >>= λ p => (f p.1).run p.2 := by
simp [bind, StateT.bind, run]
@[simp] theorem run_map {α β σ : Type u} [Monad m] [LawfulMonad m] (f : α β) (x : StateT σ m α) (s : σ) : (f <$> x).run s = (fun (p : α × σ) => (f p.1, p.2)) <$> x.run s := by
simp [Functor.map, StateT.map, run, map_eq_pure_bind]
@[simp] theorem run_get [Monad m] (s : σ) : (get : StateT σ m σ).run s = pure (s, s) := rfl
@[simp] theorem run_set [Monad m] (s s' : σ) : (set s' : StateT σ m PUnit).run s = pure (, s') := rfl
@[simp] theorem run_modify [Monad m] (f : σ σ) (s : σ) : (modify f : StateT σ m PUnit).run s = pure (, f s) := rfl
@[simp] theorem run_modifyGet [Monad m] (f : σ α × σ) (s : σ) : (modifyGet f : StateT σ m α).run s = pure ((f s).1, (f s).2) := by
simp [modifyGet, MonadStateOf.modifyGet, StateT.modifyGet, run]
@[simp] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
@[simp] theorem run_bind_lift {α σ : Type u} [Monad m] [LawfulMonad m] (x : m α) (f : α StateT σ m β) (s : σ) : (StateT.lift x >>= f).run s = x >>= fun a => (f a).run s := by
simp [StateT.lift, StateT.run, bind, StateT.bind]
@[simp] theorem run_monadLift {α σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) : (monadLift x : StateT σ m α).run s = (monadLift x : m α) >>= fun a => pure (a, s) := rfl
@[simp] theorem run_monadMap [Monad m] [MonadFunctor n m] (f : {β : Type u} n β n β) (x : StateT σ m α) (s : σ)
: (monadMap @f x : StateT σ m α).run s = monadMap @f (x.run s) := rfl
@[simp] theorem run_seq {α β σ : Type u} [Monad m] [LawfulMonad m] (f : StateT σ m (α β)) (x : StateT σ m α) (s : σ) : (f <*> x).run s = (f.run s >>= fun fs => (fun (p : α × σ) => (fs.1 p.1, p.2)) <$> x.run fs.2) := by
show (f >>= fun g => g <$> x).run s = _
simp
@[simp] theorem run_seqRight [Monad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x *> y).run s = (x.run s >>= fun p => y.run p.2) := by
show (x >>= fun _ => y).run s = _
simp
@[simp] theorem run_seqLeft {α β σ : Type u} [Monad m] (x : StateT σ m α) (y : StateT σ m β) (s : σ) : (x <* y).run s = (x.run s >>= fun p => y.run p.2 >>= fun p' => pure (p.1, p'.2)) := by
show (x >>= fun a => y >>= fun _ => pure a).run s = _
simp
theorem seqRight_eq [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) : x *> y = const α id <$> x <*> y := by
apply ext; intro s
simp [map_eq_pure_bind, const]
apply bind_congr; intro p; cases p
simp [Prod.eta]
theorem seqLeft_eq [Monad m] [LawfulMonad m] (x : StateT σ m α) (y : StateT σ m β) : x <* y = const β <$> x <*> y := by
apply ext; intro s
simp [map_eq_pure_bind]
instance [Monad m] [LawfulMonad m] : LawfulMonad (StateT σ m) where
id_map := by intros; apply ext; intros; simp[Prod.eta]
map_const := by intros; rfl
seqLeft_eq := seqLeft_eq
seqRight_eq := seqRight_eq
pure_seq := by intros; apply ext; intros; simp
bind_pure_comp := by intros; apply ext; intros; simp; apply LawfulMonad.bind_pure_comp
bind_map := by intros; rfl
pure_bind := by intros; apply ext; intros; simp
bind_assoc := by intros; apply ext; intros; simp
end StateT
/-! # EStateM -/
instance : LawfulMonad (EStateM ε σ) := .mk'
(id_map := fun x => funext <| fun s => by
dsimp only [EStateM.instMonad, EStateM.map]
match x s with
| .ok _ _ => rfl
| .error _ _ => rfl)
(pure_bind := fun _ _ => rfl)
(bind_assoc := fun x _ _ => funext <| fun s => by
dsimp only [EStateM.instMonad, EStateM.bind]
match x s with
| .ok _ _ => rfl
| .error _ _ => rfl)
(map_const := fun _ _ => rfl)

View File

@@ -10,7 +10,7 @@ import Init.Control.Except
universe u v
instance : ToBool (Option α) := Option.toBool
instance : ToBool (Option α) := Option.isSome
def OptionT (m : Type u Type v) (α : Type u) : Type v :=
m (Option α)
@@ -67,7 +67,7 @@ instance : MonadExceptOf Unit (OptionT m) where
throw := fun _ => OptionT.fail
tryCatch := OptionT.tryCatch
instance (ε : Type u) [Monad m] [MonadExceptOf ε m] : MonadExceptOf ε (OptionT m) where
instance (ε : Type u) [MonadExceptOf ε m] : MonadExceptOf ε (OptionT m) where
throw e := OptionT.mk <| throwThe ε e
tryCatch x handle := OptionT.mk <| tryCatchThe ε x handle

View File

@@ -32,7 +32,7 @@ instance : MonadControl m (ReaderT ρ m) where
restoreM x _ := x
@[always_inline]
instance ReaderT.tryFinally [MonadFinally m] [Monad m] : MonadFinally (ReaderT ρ m) where
instance ReaderT.tryFinally [MonadFinally m] : MonadFinally (ReaderT ρ m) where
tryFinally' x h ctx := tryFinally' (x ctx) (fun a? => h a? ctx)
@[reducible] def ReaderM (ρ : Type u) := ReaderT ρ Id

View File

@@ -87,7 +87,7 @@ protected def lift {α : Type u} (t : m α) : StateT σ m α :=
instance : MonadLift m (StateT σ m) := StateT.lift
@[always_inline]
instance (σ m) [Monad m] : MonadFunctor m (StateT σ m) := fun f x s => f (x s)
instance (σ m) : MonadFunctor m (StateT σ m) := fun f x s => f (x s)
@[always_inline]
instance (ε) [MonadExceptOf ε m] : MonadExceptOf ε (StateT σ m) := {

View File

@@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.Control.Lawful
import Init.Control.Lawful.Basic
/-!
The State monad transformer using CPS style.
@@ -14,16 +14,18 @@ def StateCpsT (σ : Type u) (m : Type u → Type v) (α : Type u) := (δ : Type
namespace StateCpsT
variable {α σ : Type u} {m : Type u Type v}
@[always_inline, inline]
def runK {α σ : Type u} {m : Type u Type v} (x : StateCpsT σ m α) (s : σ) (k : α σ m β) : m β :=
def runK (x : StateCpsT σ m α) (s : σ) (k : α σ m β) : m β :=
x _ s k
@[always_inline, inline]
def run {α σ : Type u} {m : Type u Type v} [Monad m] (x : StateCpsT σ m α) (s : σ) : m (α × σ) :=
def run [Monad m] (x : StateCpsT σ m α) (s : σ) : m (α × σ) :=
runK x s (fun a s => pure (a, s))
@[always_inline, inline]
def run' {α σ : Type u} {m : Type u Type v} [Monad m] (x : StateCpsT σ m α) (s : σ) : m α :=
def run' [Monad m] (x : StateCpsT σ m α) (s : σ) : m α :=
runK x s (fun a _ => pure a)
@[always_inline]
@@ -48,29 +50,29 @@ protected def lift [Monad m] (x : m α) : StateCpsT σ m α :=
instance [Monad m] : MonadLift m (StateCpsT σ m) where
monadLift := StateCpsT.lift
@[simp] theorem runK_pure {m : Type u Type v} (a : α) (s : σ) (k : α σ m β) : (pure a : StateCpsT σ m α).runK s k = k a s := rfl
@[simp] theorem runK_pure (a : α) (s : σ) (k : α σ m β) : (pure a : StateCpsT σ m α).runK s k = k a s := rfl
@[simp] theorem runK_get {m : Type u Type v} (s : σ) (k : σ σ m β) : (get : StateCpsT σ m σ).runK s k = k s s := rfl
@[simp] theorem runK_get (s : σ) (k : σ σ m β) : (get : StateCpsT σ m σ).runK s k = k s s := rfl
@[simp] theorem runK_set {m : Type u Type v} (s s' : σ) (k : PUnit σ m β) : (set s' : StateCpsT σ m PUnit).runK s k = k s' := rfl
@[simp] theorem runK_set (s s' : σ) (k : PUnit σ m β) : (set s' : StateCpsT σ m PUnit).runK s k = k s' := rfl
@[simp] theorem runK_modify {m : Type u Type v} (f : σ σ) (s : σ) (k : PUnit σ m β) : (modify f : StateCpsT σ m PUnit).runK s k = k (f s) := rfl
@[simp] theorem runK_modify (f : σ σ) (s : σ) (k : PUnit σ m β) : (modify f : StateCpsT σ m PUnit).runK s k = k (f s) := rfl
@[simp] theorem runK_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) (k : α σ m β) : (StateCpsT.lift x : StateCpsT σ m α).runK s k = x >>= (k . s) := rfl
@[simp] theorem runK_lift [Monad m] (x : m α) (s : σ) (k : α σ m β) : (StateCpsT.lift x : StateCpsT σ m α).runK s k = x >>= (k . s) := rfl
@[simp] theorem runK_monadLift {σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) (k : α σ m β)
@[simp] theorem runK_monadLift [Monad m] [MonadLiftT n m] (x : n α) (s : σ) (k : α σ m β)
: (monadLift x : StateCpsT σ m α).runK s k = (monadLift x : m α) >>= (k . s) := rfl
@[simp] theorem runK_bind_pure {α σ : Type u} [Monad m] (a : α) (f : α StateCpsT σ m β) (s : σ) (k : β σ m γ) : (pure a >>= f).runK s k = (f a).runK s k := rfl
@[simp] theorem runK_bind_pure (a : α) (f : α StateCpsT σ m β) (s : σ) (k : β σ m γ) : (pure a >>= f).runK s k = (f a).runK s k := rfl
@[simp] theorem runK_bind_lift {α σ : Type u} [Monad m] (x : m α) (f : α StateCpsT σ m β) (s : σ) (k : β σ m γ)
@[simp] theorem runK_bind_lift [Monad m] (x : m α) (f : α StateCpsT σ m β) (s : σ) (k : β σ m γ)
: (StateCpsT.lift x >>= f).runK s k = x >>= fun a => (f a).runK s k := rfl
@[simp] theorem runK_bind_get {σ : Type u} [Monad m] (f : σ StateCpsT σ m β) (s : σ) (k : β σ m γ) : (get >>= f).runK s k = (f s).runK s k := rfl
@[simp] theorem runK_bind_get (f : σ StateCpsT σ m β) (s : σ) (k : β σ m γ) : (get >>= f).runK s k = (f s).runK s k := rfl
@[simp] theorem runK_bind_set {σ : Type u} [Monad m] (f : PUnit StateCpsT σ m β) (s s' : σ) (k : β σ m γ) : (set s' >>= f).runK s k = (f ).runK s' k := rfl
@[simp] theorem runK_bind_set (f : PUnit StateCpsT σ m β) (s s' : σ) (k : β σ m γ) : (set s' >>= f).runK s k = (f ).runK s' k := rfl
@[simp] theorem runK_bind_modify {σ : Type u} [Monad m] (f : σ σ) (g : PUnit StateCpsT σ m β) (s : σ) (k : β σ m γ) : (modify f >>= g).runK s k = (g ).runK (f s) k := rfl
@[simp] theorem runK_bind_modify (f : σ σ) (g : PUnit StateCpsT σ m β) (s : σ) (k : β σ m γ) : (modify f >>= g).runK s k = (g ).runK (f s) k := rfl
@[simp] theorem run_eq [Monad m] (x : StateCpsT σ m α) (s : σ) : x.run s = x.runK s (fun a s => pure (a, s)) := rfl

View File

@@ -34,22 +34,22 @@ protected def lift (x : m α) : StateRefT' ω σ m α :=
instance [Monad m] : Monad (StateRefT' ω σ m) := inferInstanceAs (Monad (ReaderT _ _))
instance : MonadLift m (StateRefT' ω σ m) := StateRefT'.lift
instance (σ m) [Monad m] : MonadFunctor m (StateRefT' ω σ m) := inferInstanceAs (MonadFunctor m (ReaderT _ _))
instance (σ m) : MonadFunctor m (StateRefT' ω σ m) := inferInstanceAs (MonadFunctor m (ReaderT _ _))
instance [Alternative m] [Monad m] : Alternative (StateRefT' ω σ m) := inferInstanceAs (Alternative (ReaderT _ _))
@[inline]
protected def get [Monad m] [MonadLiftT (ST ω) m] : StateRefT' ω σ m σ :=
protected def get [MonadLiftT (ST ω) m] : StateRefT' ω σ m σ :=
fun ref => ref.get
@[inline]
protected def set [Monad m] [MonadLiftT (ST ω) m] (s : σ) : StateRefT' ω σ m PUnit :=
protected def set [MonadLiftT (ST ω) m] (s : σ) : StateRefT' ω σ m PUnit :=
fun ref => ref.set s
@[inline]
protected def modifyGet [Monad m] [MonadLiftT (ST ω) m] (f : σ α × σ) : StateRefT' ω σ m α :=
protected def modifyGet [MonadLiftT (ST ω) m] (f : σ α × σ) : StateRefT' ω σ m α :=
fun ref => ref.modifyGet f
instance [MonadLiftT (ST ω) m] [Monad m] : MonadStateOf σ (StateRefT' ω σ m) where
instance [MonadLiftT (ST ω) m] : MonadStateOf σ (StateRefT' ω σ m) where
get := StateRefT'.get
set := StateRefT'.set
modifyGet := StateRefT'.modifyGet

View File

@@ -6,7 +6,7 @@ Authors: Leonardo de Moura
Notation for operators defined at Prelude.lean
-/
prelude
import Init.NotationExtra
import Init.Tactics
namespace Lean.Parser.Tactic.Conv
@@ -54,6 +54,10 @@ syntax (name := lhs) "lhs" : conv
(In general, for an `n`-ary operator, it traverses into the last argument.) -/
syntax (name := rhs) "rhs" : conv
/-- Traverses into the function of a (unary) function application.
For example, `| f a b` turns into `| f a`. (Use `arg 0` to traverse into `f`.) -/
syntax (name := «fun») "fun" : conv
/-- Reduces the target to Weak Head Normal Form. This reduces definitions
in "head position" until a constructor is exposed. For example, `List.map f [a, b, c]`
weak head normalizes to `f a :: List.map f [b, c]`. -/
@@ -74,7 +78,8 @@ syntax (name := congr) "congr" : conv
* `arg i` traverses into the `i`'th argument of the target. For example if the
target is `f a b c d` then `arg 1` traverses to `a` and `arg 3` traverses to `c`.
* `arg @i` is the same as `arg i` but it counts all arguments instead of just the
explicit arguments. -/
explicit arguments.
* `arg 0` traverses into the function. If the target is `f a b c d`, `arg 0` traverses into `f`. -/
syntax (name := arg) "arg " "@"? num : conv
/-- `ext x` traverses into a binder (a `fun x => e` or `∀ x, e` expression)
@@ -151,7 +156,6 @@ match [a, b] with
simplifies to `a`. -/
syntax (name := simpMatch) "simp_match" : conv
/-- Executes the given tactic block without converting `conv` goal into a regular goal. -/
syntax (name := nestedTacticCore) "tactic'" " => " tacticSeq : conv
@@ -197,7 +201,7 @@ macro (name := anyGoals) tk:"any_goals " s:convSeq : conv =>
with inaccessible names to the given names.
* `case tag₁ | tag₂ => tac` is equivalent to `(case tag₁ => tac); (case tag₂ => tac)`.
-/
macro (name := case) tk:"case " args:sepBy1(caseArg, " | ") arr:" => " s:convSeq : conv =>
macro (name := case) tk:"case " args:sepBy1(caseArg, "|") arr:" => " s:convSeq : conv =>
`(conv| tactic' => case%$tk $args|* =>%$arr conv' => ($s); all_goals rfl)
/--
@@ -206,7 +210,7 @@ has been solved after applying `tac`, nor admits the goal if `tac` failed.
Recall that `case` closes the goal using `sorry` when `tac` fails, and
the tactic execution is not interrupted.
-/
macro (name := case') tk:"case' " args:sepBy1(caseArg, " | ") arr:" => " s:convSeq : conv =>
macro (name := case') tk:"case' " args:sepBy1(caseArg, "|") arr:" => " s:convSeq : conv =>
`(conv| tactic' => case'%$tk $args|* =>%$arr conv' => $s)
/--
@@ -303,4 +307,7 @@ Basic forms:
-- refer to the syntax category instead of this syntax
syntax (name := conv) "conv" (" at " ident)? (" in " (occs)? term)? " => " convSeq : tactic
/-- `norm_cast` tactic in `conv` mode. -/
syntax (name := normCast) "norm_cast" : conv
end Lean.Parser.Tactic.Conv

View File

@@ -17,7 +17,9 @@ universe u v w
at the application site itself (by comparison to the `@[inline]` attribute,
which applies to all applications of the function).
-/
def inline {α : Sort u} (a : α) : α := a
@[simp] def inline {α : Sort u} (a : α) : α := a
theorem id_def {α : Sort u} (a : α) : id a = a := rfl
/--
`flip f a b` is `f b a`. It is useful for "point-free" programming,
@@ -32,8 +34,32 @@ and `flip (·<·)` is the greater-than relation.
@[simp] theorem Function.comp_apply {f : β δ} {g : α β} {x : α} : comp f g x = f (g x) := rfl
theorem Function.comp_def {α β δ} (f : β δ) (g : α β) : f g = fun x => f (g x) := rfl
attribute [simp] namedPattern
/--
`Empty.elim : Empty → C` says that a value of any type can be constructed from
`Empty`. This can be thought of as a compiler-checked assertion that a code path is unreachable.
This is a non-dependent variant of `Empty.rec`.
-/
@[macro_inline] def Empty.elim {C : Sort u} : Empty C := Empty.rec
/-- Decidable equality for Empty -/
instance : DecidableEq Empty := fun a => a.elim
/--
`PEmpty.elim : Empty → C` says that a value of any type can be constructed from
`PEmpty`. This can be thought of as a compiler-checked assertion that a code path is unreachable.
This is a non-dependent variant of `PEmpty.rec`.
-/
@[macro_inline] def PEmpty.elim {C : Sort _} : PEmpty C := fun a => nomatch a
/-- Decidable equality for PEmpty -/
instance : DecidableEq PEmpty := fun a => a.elim
/--
Thunks are "lazy" values that are evaluated when first accessed using `Thunk.get/map/bind`.
The value is then stored and not recomputed for all further accesses. -/
@@ -78,6 +104,8 @@ instance thunkCoe : CoeTail α (Thunk α) where
abbrev Eq.ndrecOn.{u1, u2} {α : Sort u2} {a : α} {motive : α Sort u1} {b : α} (h : a = b) (m : motive a) : motive b :=
Eq.ndrec m h
/-! # definitions -/
/--
If and only if, or logical bi-implication. `a ↔ b` means that `a` implies `b` and vice versa.
By `propext`, this implies that `a` and `b` are equal and hence any expression involving `a`
@@ -126,6 +154,10 @@ inductive PSum (α : Sort u) (β : Sort v) where
@[inherit_doc] infixr:30 " ⊕' " => PSum
instance {α β} [Inhabited α] : Inhabited (PSum α β) := PSum.inl default
instance {α β} [Inhabited β] : Inhabited (PSum α β) := PSum.inr default
/--
`Sigma β`, also denoted `Σ a : α, β a` or `(a : α) × β a`, is the type of dependent pairs
whose first component is `a : α` and whose second component is `b : β a`
@@ -133,6 +165,7 @@ whose first component is `a : α` and whose second component is `b : β a`
It is sometimes known as the dependent sum type, since it is the type level version
of an indexed summation.
-/
@[pp_using_anonymous_constructor]
structure Sigma {α : Type u} (β : α Type v) where
/-- Constructor for a dependent pair. If `a : α` and `b : β a` then `⟨a, b⟩ : Sigma β`.
(This will usually require a type ascription to determine `β`
@@ -158,6 +191,7 @@ which can cause problems for universe level unification,
because the equation `max 1 u v = ?u + 1` has no solution in level arithmetic.
`PSigma` is usually only used in automation that constructs pairs of arbitrary types.
-/
@[pp_using_anonymous_constructor]
structure PSigma {α : Sort u} (β : α Sort v) where
/-- Constructor for a dependent pair. If `a : α` and `b : β a` then `⟨a, b⟩ : PSigma β`.
(This will usually require a type ascription to determine `β`
@@ -342,6 +376,70 @@ class HasEquiv (α : Sort u) where
@[inherit_doc] infix:50 "" => HasEquiv.Equiv
/-! # set notation -/
/-- Notation type class for the subset relation `⊆`. -/
class HasSubset (α : Type u) where
/-- Subset relation: `a ⊆ b` -/
Subset : α α Prop
export HasSubset (Subset)
/-- Notation type class for the strict subset relation `⊂`. -/
class HasSSubset (α : Type u) where
/-- Strict subset relation: `a ⊂ b` -/
SSubset : α α Prop
export HasSSubset (SSubset)
/-- Superset relation: `a ⊇ b` -/
abbrev Superset [HasSubset α] (a b : α) := Subset b a
/-- Strict superset relation: `a ⊃ b` -/
abbrev SSuperset [HasSSubset α] (a b : α) := SSubset b a
/-- Notation type class for the union operation ``. -/
class Union (α : Type u) where
/-- `a b` is the union of`a` and `b`. -/
union : α α α
/-- Notation type class for the intersection operation `∩`. -/
class Inter (α : Type u) where
/-- `a ∩ b` is the intersection of`a` and `b`. -/
inter : α α α
/-- Notation type class for the set difference `\`. -/
class SDiff (α : Type u) where
/--
`a \ b` is the set difference of `a` and `b`,
consisting of all elements in `a` that are not in `b`.
-/
sdiff : α α α
/-- Subset relation: `a ⊆ b` -/
infix:50 "" => Subset
/-- Strict subset relation: `a ⊂ b` -/
infix:50 "" => SSubset
/-- Superset relation: `a ⊇ b` -/
infix:50 "" => Superset
/-- Strict superset relation: `a ⊃ b` -/
infix:50 "" => SSuperset
/-- `a b` is the union of`a` and `b`. -/
infixl:65 " " => Union.union
/-- `a ∩ b` is the intersection of`a` and `b`. -/
infixl:70 "" => Inter.inter
/--
`a \ b` is the set difference of `a` and `b`,
consisting of all elements in `a` that are not in `b`.
-/
infix:70 " \\ " => SDiff.sdiff
/-! # collections -/
/-- `EmptyCollection α` is the typeclass which supports the notation `∅`, also written as `{}`. -/
class EmptyCollection (α : Type u) where
/-- `∅` or `{}` is the empty set or empty collection.
@@ -351,6 +449,36 @@ class EmptyCollection (α : Type u) where
@[inherit_doc] notation "{" "}" => EmptyCollection.emptyCollection
@[inherit_doc] notation "" => EmptyCollection.emptyCollection
/--
Type class for the `insert` operation.
Used to implement the `{ a, b, c }` syntax.
-/
class Insert (α : outParam <| Type u) (γ : Type v) where
/-- `insert x xs` inserts the element `x` into the collection `xs`. -/
insert : α γ γ
export Insert (insert)
/--
Type class for the `singleton` operation.
Used to implement the `{ a, b, c }` syntax.
-/
class Singleton (α : outParam <| Type u) (β : Type v) where
/-- `singleton x` is a collection with the single element `x` (notation: `{x}`). -/
singleton : α β
export Singleton (singleton)
/-- `insert x ∅ = {x}` -/
class LawfulSingleton (α : Type u) (β : Type v) [EmptyCollection β] [Insert α β] [Singleton α β] :
Prop where
/-- `insert x ∅ = {x}` -/
insert_emptyc_eq (x : α) : (insert x : β) = singleton x
export LawfulSingleton (insert_emptyc_eq)
/-- Type class used to implement the notation `{ a ∈ c | p a }` -/
class Sep (α : outParam <| Type u) (γ : Type v) where
/-- Computes `{ a ∈ c | p a }`. -/
sep : (α Prop) γ γ
/--
`Task α` is a primitive for asynchronous computation.
It represents a computation that will resolve to a value of type `α`,
@@ -514,7 +642,7 @@ instance : LawfulBEq String := inferInstance
/-! # Logical connectives and equality -/
@[inherit_doc True.intro] def trivial : True :=
@[inherit_doc True.intro] theorem trivial : True :=
theorem mt {a b : Prop} (h₁ : a b) (h₂ : ¬b) : ¬a :=
fun ha => h₂ (h₁ ha)
@@ -525,9 +653,7 @@ theorem not_not_intro {p : Prop} (h : p) : ¬ ¬ p :=
fun hn : ¬ p => hn h
-- proof irrelevance is built in
theorem proofIrrel {a : Prop} (h₁ h₂ : a) : h₁ = h₂ := rfl
theorem id.def {α : Sort u} (a : α) : id a = a := rfl
theorem proof_irrel {a : Prop} (h₁ h₂ : a) : h₁ = h₂ := rfl
/--
If `h : α = β` is a proof of type equality, then `h.mp : α → β` is the induced
@@ -553,7 +679,7 @@ You can prove theorems about the resulting element by induction on `h`, since
theorem Eq.substr {α : Sort u} {p : α Prop} {a b : α} (h₁ : b = a) (h₂ : p a) : p b :=
h₁ h₂
theorem cast_eq {α : Sort u} (h : α = α) (a : α) : cast h a = a :=
@[simp] theorem cast_eq {α : Sort u} (h : α = α) (a : α) : cast h a = a :=
rfl
/--
@@ -575,8 +701,9 @@ theorem Ne.elim (h : a ≠ b) : a = b → False := h
theorem Ne.irrefl (h : a a) : False := h rfl
theorem Ne.symm (h : a b) : b a :=
fun h₁ => h (h₁.symm)
theorem Ne.symm (h : a b) : b a := fun h₁ => h (h₁.symm)
theorem ne_comm {α} {a b : α} : a b b a := Ne.symm, Ne.symm
theorem false_of_ne : a a False := Ne.irrefl
@@ -588,8 +715,8 @@ theorem ne_true_of_not : ¬p → p ≠ True :=
have : ¬True := h hnp
this trivial
theorem true_ne_false : ¬True = False :=
ne_false_of_self trivial
theorem true_ne_false : ¬True = False := ne_false_of_self trivial
theorem false_ne_true : False True := fun h => h.symm trivial
end Ne
@@ -612,13 +739,16 @@ theorem beq_false_of_ne [BEq α] [LawfulBEq α] {a b : α} (h : a ≠ b) : (a ==
section
variable {α β φ : Sort u} {a a' : α} {b b' : β} {c : φ}
theorem HEq.ndrec.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} β Sort u1} (m : motive a) {β : Sort u2} {b : β} (h : HEq a b) : motive b :=
/-- Non-dependent recursor for `HEq` -/
noncomputable def HEq.ndrec.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} β Sort u1} (m : motive a) {β : Sort u2} {b : β} (h : HEq a b) : motive b :=
h.rec m
theorem HEq.ndrecOn.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} β Sort u1} {β : Sort u2} {b : β} (h : HEq a b) (m : motive a) : motive b :=
/-- `HEq.ndrec` variant -/
noncomputable def HEq.ndrecOn.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} β Sort u1} {β : Sort u2} {b : β} (h : HEq a b) (m : motive a) : motive b :=
h.rec m
theorem HEq.elim {α : Sort u} {a : α} {p : α Sort v} {b : α} (h₁ : HEq a b) (h₂ : p a) : p b :=
/-- `HEq.ndrec` variant -/
noncomputable def HEq.elim {α : Sort u} {a : α} {p : α Sort v} {b : α} (h₁ : HEq a b) (h₂ : p a) : p b :=
eq_of_heq h₁ h₂
theorem HEq.subst {p : (T : Sort u) T Prop} (h₁ : HEq a b) (h₂ : p α a) : p β b :=
@@ -666,22 +796,31 @@ theorem Iff.refl (a : Prop) : a ↔ a :=
protected theorem Iff.rfl {a : Prop} : a a :=
Iff.refl a
macro_rules | `(tactic| rfl) => `(tactic| exact Iff.rfl)
theorem Iff.of_eq (h : a = b) : a b := h Iff.rfl
theorem Iff.trans (h₁ : a b) (h₂ : b c) : a c :=
Iff.intro
(fun ha => Iff.mp h₂ (Iff.mp h₁ ha))
(fun hc => Iff.mpr h₁ (Iff.mpr h₂ hc))
Iff.intro (h₂.mp h₁.mp) (h₁.mpr h₂.mpr)
theorem Iff.symm (h : a b) : b a :=
Iff.intro (Iff.mpr h) (Iff.mp h)
-- This is needed for `calc` to work with `iff`.
instance : Trans Iff Iff Iff where
trans := Iff.trans
theorem Iff.comm : (a b) (b a) :=
Iff.intro Iff.symm Iff.symm
theorem Eq.comm {a b : α} : a = b b = a := Iff.intro Eq.symm Eq.symm
theorem eq_comm {a b : α} : a = b b = a := Eq.comm
theorem Iff.of_eq (h : a = b) : a b :=
h Iff.refl _
theorem Iff.symm (h : a b) : b a := Iff.intro h.mpr h.mp
theorem Iff.comm: (a b) (b a) := Iff.intro Iff.symm Iff.symm
theorem iff_comm : (a b) (b a) := Iff.comm
theorem And.comm : a b b a := by
constructor <;> intro h₁, h₂ <;> exact h₂, h₁
theorem And.symm : a b b a := fun ha, hb => hb, ha
theorem And.comm : a b b a := Iff.intro And.symm And.symm
theorem and_comm : a b b a := And.comm
theorem Or.symm : a b b a := .rec .inr .inl
theorem Or.comm : a b b a := Iff.intro Or.symm Or.symm
theorem or_comm : a b b a := Or.comm
/-! # Exists -/
@@ -881,8 +1020,13 @@ protected theorem Subsingleton.helim {α β : Sort u} [h₁ : Subsingleton α] (
apply heq_of_eq
apply Subsingleton.elim
instance (p : Prop) : Subsingleton p :=
fun a b => proofIrrel a b
instance (p : Prop) : Subsingleton p := fun a b => proof_irrel a b
instance : Subsingleton Empty := (·.elim)
instance : Subsingleton PEmpty := (·.elim)
instance [Subsingleton α] [Subsingleton β] : Subsingleton (α × β) :=
fun {..} {..} => by congr <;> apply Subsingleton.elim
instance (p : Prop) : Subsingleton (Decidable p) :=
Subsingleton.intro fun
@@ -893,6 +1037,9 @@ instance (p : Prop) : Subsingleton (Decidable p) :=
| isTrue t₂ => absurd t₂ f₁
| isFalse _ => rfl
example [Subsingleton α] (p : α Prop) : Subsingleton (Subtype p) :=
fun x, _ y, _ => by congr; exact Subsingleton.elim x y
theorem recSubsingleton
{p : Prop} [h : Decidable p]
{h₁ : p Sort u}
@@ -967,9 +1114,6 @@ theorem eta (a : {x // p x}) (h : p (val a)) : mk (val a) h = a := by
cases a
exact rfl
instance {α : Type u} {p : α Prop} {a : α} (h : p a) : Inhabited {x // p x} where
default := a, h
instance {α : Type u} {p : α Prop} [DecidableEq α] : DecidableEq {x : α // p x} :=
fun a, h₁ b, h₂ =>
if h : a = b then isTrue (by subst h; exact rfl)
@@ -1029,7 +1173,7 @@ def Prod.lexLt [LT α] [LT β] (s : α × β) (t : α × β) : Prop :=
s.1 < t.1 (s.1 = t.1 s.2 < t.2)
instance Prod.lexLtDec
[LT α] [LT β] [DecidableEq α] [DecidableEq β]
[LT α] [LT β] [DecidableEq α]
[(a b : α) Decidable (a < b)] [(a b : β) Decidable (a < b)]
: (s t : α × β) Decidable (Prod.lexLt s t) :=
fun _ _ => inferInstanceAs (Decidable (_ _))
@@ -1047,6 +1191,11 @@ def Prod.map {α₁ : Type u₁} {α₂ : Type u₂} {β₁ : Type v₁} {β₂
(f : α₁ α₂) (g : β₁ β₂) : α₁ × β₁ α₂ × β₂
| (a, b) => (f a, g b)
@[simp] theorem Prod.map_apply (f : α β) (g : γ δ) (x) (y) :
Prod.map f g (x, y) = (f x, g y) := rfl
@[simp] theorem Prod.map_fst (f : α β) (g : γ δ) (x) : (Prod.map f g x).1 = f x.1 := rfl
@[simp] theorem Prod.map_snd (f : α β) (g : γ δ) (x) : (Prod.map f g x).2 = g x.2 := rfl
/-! # Dependent products -/
theorem ex_of_PSigma {α : Type u} {p : α Prop} : (PSigma (fun x => p x)) Exists (fun x => p x)
@@ -1161,7 +1310,6 @@ gen_injective_theorems% Fin
gen_injective_theorems% Array
gen_injective_theorems% Sum
gen_injective_theorems% PSum
gen_injective_theorems% Nat
gen_injective_theorems% Option
gen_injective_theorems% List
gen_injective_theorems% Except
@@ -1169,15 +1317,126 @@ gen_injective_theorems% EStateM.Result
gen_injective_theorems% Lean.Name
gen_injective_theorems% Lean.Syntax
theorem Nat.succ.inj {m n : Nat} : m.succ = n.succ m = n :=
fun x => Nat.noConfusion x id
theorem Nat.succ.injEq (u v : Nat) : (u.succ = v.succ) = (u = v) :=
Eq.propIntro Nat.succ.inj (congrArg Nat.succ)
@[simp] theorem beq_iff_eq [BEq α] [LawfulBEq α] (a b : α) : a == b a = b :=
eq_of_beq, by intro h; subst h; exact LawfulBEq.rfl
/-! # Quotients -/
/-! # Prop lemmas -/
/-- *Ex falso* for negation: from `¬a` and `a` anything follows. This is the same as `absurd` with
the arguments flipped, but it is in the `Not` namespace so that projection notation can be used. -/
def Not.elim {α : Sort _} (H1 : ¬a) (H2 : a) : α := absurd H2 H1
/-- Non-dependent eliminator for `And`. -/
abbrev And.elim (f : a b α) (h : a b) : α := f h.left h.right
/-- Non-dependent eliminator for `Iff`. -/
def Iff.elim (f : (a b) (b a) α) (h : a b) : α := f h.mp h.mpr
/-- Iff can now be used to do substitutions in a calculation -/
theorem Iff.subst {a b : Prop} {p : Prop Prop} (h₁ : a b) (h₂ : p a) : p b :=
Eq.subst (propext h₁) h₂
theorem Not.intro {a : Prop} (h : a False) : ¬a := h
theorem Not.imp {a b : Prop} (H2 : ¬b) (H1 : a b) : ¬a := mt H1 H2
theorem not_congr (h : a b) : ¬a ¬b := mt h.2, mt h.1
theorem not_not_not : ¬¬¬a ¬a := mt not_not_intro, not_not_intro
theorem iff_of_true (ha : a) (hb : b) : a b := Iff.intro (fun _ => hb) (fun _ => ha)
theorem iff_of_false (ha : ¬a) (hb : ¬b) : a b := Iff.intro ha.elim hb.elim
theorem iff_true_left (ha : a) : (a b) b := Iff.intro (·.mp ha) (iff_of_true ha)
theorem iff_true_right (ha : a) : (b a) b := Iff.comm.trans (iff_true_left ha)
theorem iff_false_left (ha : ¬a) : (a b) ¬b := Iff.intro (mt ·.mpr ha) (iff_of_false ha)
theorem iff_false_right (ha : ¬a) : (b a) ¬b := Iff.comm.trans (iff_false_left ha)
theorem of_iff_true (h : a True) : a := h.mpr trivial
theorem iff_true_intro (h : a) : a True := iff_of_true h trivial
theorem not_of_iff_false : (p False) ¬p := Iff.mp
theorem iff_false_intro (h : ¬a) : a False := iff_of_false h id
theorem not_iff_false_intro (h : a) : ¬a False := iff_false_intro (not_not_intro h)
theorem not_true : (¬True) False := iff_false_intro (not_not_intro trivial)
theorem not_false_iff : (¬False) True := iff_true_intro not_false
theorem Eq.to_iff : a = b (a b) := Iff.of_eq
theorem iff_of_eq : a = b (a b) := Iff.of_eq
theorem neq_of_not_iff : ¬(a b) a b := mt Iff.of_eq
theorem iff_iff_eq : (a b) a = b := Iff.intro propext Iff.of_eq
@[simp] theorem eq_iff_iff : (a = b) (a b) := iff_iff_eq.symm
theorem eq_self_iff_true (a : α) : a = a True := iff_true_intro rfl
theorem ne_self_iff_false (a : α) : a a False := not_iff_false_intro rfl
theorem false_of_true_iff_false (h : True False) : False := h.mp trivial
theorem false_of_true_eq_false (h : True = False) : False := false_of_true_iff_false (Iff.of_eq h)
theorem true_eq_false_of_false : False (True = False) := False.elim
theorem iff_def : (a b) (a b) (b a) := iff_iff_implies_and_implies a b
theorem iff_def' : (a b) (b a) (a b) := Iff.trans iff_def And.comm
theorem true_iff_false : (True False) False := iff_false_intro (·.mp True.intro)
theorem false_iff_true : (False True) False := iff_false_intro (·.mpr True.intro)
theorem iff_not_self : ¬(a ¬a) | H => let f h := H.1 h h; f (H.2 f)
theorem heq_self_iff_true (a : α) : HEq a a True := iff_true_intro HEq.rfl
/-! ## implies -/
theorem not_not_of_not_imp : ¬(a b) ¬¬a := mt Not.elim
theorem not_of_not_imp {a : Prop} : ¬(a b) ¬b := mt fun h _ => h
@[simp] theorem imp_not_self : (a ¬a) ¬a := Iff.intro (fun h ha => h ha ha) (fun h _ => h)
theorem imp_intro {α β : Prop} (h : α) : β α := fun _ => h
theorem imp_imp_imp {a b c d : Prop} (h₀ : c a) (h₁ : b d) : (a b) (c d) := (h₁ · h₀)
theorem imp_iff_right {a : Prop} (ha : a) : (a b) b := Iff.intro (· ha) (fun a _ => a)
-- This is not marked `@[simp]` because we have `implies_true : (α → True) = True`
theorem imp_true_iff (α : Sort u) : (α True) True := iff_true_intro (fun _ => trivial)
theorem false_imp_iff (a : Prop) : (False a) True := iff_true_intro False.elim
theorem true_imp_iff (α : Prop) : (True α) α := imp_iff_right True.intro
@[simp high] theorem imp_self : (a a) True := iff_true_intro id
@[simp] theorem imp_false : (a False) ¬a := Iff.rfl
theorem imp.swap : (a b c) (b a c) := Iff.intro flip flip
theorem imp_not_comm : (a ¬b) (b ¬a) := imp.swap
theorem imp_congr_left (h : a b) : (a c) (b c) := Iff.intro (· h.mpr) (· h.mp)
theorem imp_congr_right (h : a (b c)) : (a b) (a c) :=
Iff.intro (fun hab ha => (h ha).mp (hab ha)) (fun hcd ha => (h ha).mpr (hcd ha))
theorem imp_congr_ctx (h₁ : a c) (h₂ : c (b d)) : (a b) (c d) :=
Iff.trans (imp_congr_left h₁) (imp_congr_right h₂)
theorem imp_congr (h₁ : a c) (h₂ : b d) : (a b) (c d) := imp_congr_ctx h₁ fun _ => h₂
theorem imp_iff_not (hb : ¬b) : a b ¬a := imp_congr_right fun _ => iff_false_intro hb
/-! # Quotients -/
namespace Quot
/--
The **quotient axiom**, or at least the nontrivial part of the quotient
@@ -1344,7 +1603,7 @@ protected def mk' {α : Sort u} [s : Setoid α] (a : α) : Quotient s :=
The analogue of `Quot.sound`: If `a` and `b` are related by the equivalence relation,
then they have equal equivalence classes.
-/
def sound {α : Sort u} {s : Setoid α} {a b : α} : a b Quotient.mk s a = Quotient.mk s b :=
theorem sound {α : Sort u} {s : Setoid α} {a b : α} : a b Quotient.mk s a = Quotient.mk s b :=
Quot.sound
/--
@@ -1685,6 +1944,18 @@ axiom ofReduceNat (a b : Nat) (h : reduceNat a = b) : a = b
end Lean
@[simp] theorem ge_iff_le [LE α] {x y : α} : x y y x := Iff.rfl
@[simp] theorem gt_iff_lt [LT α] {x y : α} : x > y y < x := Iff.rfl
theorem le_of_eq_of_le {a b c : α} [LE α] (h₁ : a = b) (h₂ : b c) : a c := h₁ h₂
theorem le_of_le_of_eq {a b c : α} [LE α] (h₁ : a b) (h₂ : b = c) : a c := h₂ h₁
theorem lt_of_eq_of_lt {a b c : α} [LT α] (h₁ : a = b) (h₂ : b < c) : a < c := h₁ h₂
theorem lt_of_lt_of_eq {a b c : α} [LT α] (h₁ : a < b) (h₂ : b = c) : a < c := h₂ h₁
namespace Std
variable {α : Sort u}
@@ -1771,4 +2042,8 @@ class LawfulCommIdentity (op : ααα) (o : outParam α) [hc : Commuta
left_id a := Eq.trans (hc.comm o a) (right_id a)
right_id a := Eq.trans (hc.comm a o) (left_id a)
instance : Commutative Or := fun _ _ => propext or_comm
instance : Commutative And := fun _ _ => propext and_comm
instance : Commutative Iff := fun _ _ => propext iff_comm
end Std

View File

@@ -6,11 +6,15 @@ Authors: Leonardo de Moura
prelude
import Init.Data.Basic
import Init.Data.Nat
import Init.Data.Bool
import Init.Data.BitVec
import Init.Data.Cast
import Init.Data.Char
import Init.Data.String
import Init.Data.List
import Init.Data.Int
import Init.Data.Array
import Init.Data.Array.Subarray.Split
import Init.Data.ByteArray
import Init.Data.FloatArray
import Init.Data.Fin
@@ -29,3 +33,5 @@ import Init.Data.Prod
import Init.Data.AC
import Init.Data.Queue
import Init.Data.Channel
import Init.Data.Cast
import Init.Data.Sum

View File

@@ -106,7 +106,7 @@ def norm [info : ContextInformation α] (ctx : α) (e : Expr) : List Nat :=
let xs := if info.isComm ctx then sort xs else xs
if info.isIdem ctx then mergeIdem xs else xs
theorem List.two_step_induction
noncomputable def List.two_step_induction
{motive : List Nat Sort u}
(l : List Nat)
(empty : motive [])
@@ -146,22 +146,22 @@ theorem Context.evalList_mergeIdem (ctx : Context α) (h : ContextInformation.is
| nil =>
simp [mergeIdem, mergeIdem.loop]
split
case inl h₂ => simp [evalList, h₂, h.1, EvalInformation.evalOp]
rfl
next h₂ => simp [evalList, h₂, h.1, EvalInformation.evalOp]
next => rfl
| cons z zs =>
by_cases h₂ : x = y
case inl =>
case pos =>
rw [h₂, mergeIdem_head, ih]
simp [evalList, ctx.assoc.1, h.1, EvalInformation.evalOp]
case inr =>
case neg =>
rw [mergeIdem_head2]
by_cases h₃ : y = z
case inl =>
case pos =>
simp [mergeIdem_head, h₃, evalList]
cases h₄ : mergeIdem (z :: zs) with
| nil => apply absurd h₄; apply mergeIdem_nonEmpty; simp
| cons u us => simp_all [mergeIdem, mergeIdem.loop, evalList]
case inr =>
case neg =>
simp [mergeIdem_head2, h₃, evalList] at *
rw [ih]
assumption
@@ -191,11 +191,11 @@ theorem Context.evalList_insert
. simp [evalList, h.1, EvalInformation.evalOp]
| step y z zs ih =>
simp [insert] at *; split
case inl => rfl
case inr =>
next => rfl
next =>
split
case inl => simp [evalList, EvalInformation.evalOp]; rw [h.1, ctx.assoc.1, h.1 (evalList _ _ _)]
case inr => simp_all [evalList, EvalInformation.evalOp]; rw [h.1, ctx.assoc.1, h.1 (evalList _ _ _)]
next => simp [evalList, EvalInformation.evalOp]; rw [h.1, ctx.assoc.1, h.1 (evalList _ _ _)]
next => simp_all [evalList, EvalInformation.evalOp]; rw [h.1, ctx.assoc.1, h.1 (evalList _ _ _)]
theorem Context.evalList_sort_congr
(ctx : Context α)

View File

@@ -11,3 +11,4 @@ import Init.Data.Array.InsertionSort
import Init.Data.Array.DecidableEq
import Init.Data.Array.Mem
import Init.Data.Array.BasicAux
import Init.Data.Array.Lemmas

View File

@@ -10,7 +10,7 @@ import Init.Data.Fin.Basic
import Init.Data.UInt.Basic
import Init.Data.Repr
import Init.Data.ToString.Basic
import Init.Util
import Init.GetElem
universe u v w
namespace Array
@@ -21,6 +21,22 @@ def mkArray {α : Type u} (n : Nat) (v : α) : Array α := {
data := List.replicate n v
}
/--
`ofFn f` with `f : Fin n → α` returns the list whose ith element is `f i`.
```
ofFn f = #[f 0, f 1, ... , f(n - 1)]
``` -/
def ofFn {n} (f : Fin n α) : Array α := go 0 (mkEmpty n) where
/-- Auxiliary for `ofFn`. `ofFn.go f i acc = acc ++ #[f i, ..., f(n - 1)]` -/
go (i : Nat) (acc : Array α) : Array α :=
if h : i < n then go (i+1) (acc.push (f i, h)) else acc
termination_by n - i
decreasing_by simp_wf; decreasing_trivial_pre_omega
/-- The array `#[0, 1, ..., n - 1]`. -/
def range (n : Nat) : Array Nat :=
n.fold (flip Array.push) (mkEmpty n)
@[simp] theorem size_mkArray (n : Nat) (v : α) : (mkArray n v).size = n :=
List.length_replicate ..
@@ -28,7 +44,7 @@ instance : EmptyCollection (Array α) := ⟨Array.empty⟩
instance : Inhabited (Array α) where
default := Array.empty
def isEmpty (a : Array α) : Bool :=
@[simp] def isEmpty (a : Array α) : Bool :=
a.size = 0
def singleton (v : α) : Array α :=
@@ -37,13 +53,15 @@ def singleton (v : α) : Array α :=
/-- Low-level version of `fget` which is as fast as a C array read.
`Fin` values are represented as tag pointers in the Lean runtime. Thus,
`fget` may be slightly slower than `uget`. -/
@[extern "lean_array_uget"]
@[extern "lean_array_uget", simp]
def uget (a : @& Array α) (i : USize) (h : i.toNat < a.size) : α :=
a[i.toNat]
instance : GetElem (Array α) USize α fun xs i => i.toNat < xs.size where
getElem xs i h := xs.uget i h
instance : LawfulGetElem (Array α) USize α fun xs i => i.toNat < xs.size where
def back [Inhabited α] (a : Array α) : α :=
a.get! (a.size - 1)
@@ -289,6 +307,7 @@ def mapM {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (f : α
else
pure r
termination_by as.size - i
decreasing_by simp_wf; decreasing_trivial_pre_omega
map 0 (mkEmpty as.size)
@[inline]
@@ -361,6 +380,7 @@ def anyM {α : Type u} {m : Type → Type w} [Monad m] (p : α → m Bool) (as :
else
pure false
termination_by stop - j
decreasing_by simp_wf; decreasing_trivial_pre_omega
loop start
if h : stop as.size then
any stop h
@@ -413,6 +433,10 @@ def map {α : Type u} {β : Type v} (f : α → β) (as : Array α) : Array β :
def mapIdx {α : Type u} {β : Type v} (as : Array α) (f : Fin as.size α β) : Array β :=
Id.run <| as.mapIdxM f
/-- Turns `#[a, b]` into `#[(a, 0), (b, 1)]`. -/
def zipWithIndex (arr : Array α) : Array (α × Nat) :=
arr.mapIdx fun i a => (a, i)
@[inline]
def find? {α : Type} (as : Array α) (p : α Bool) : Option α :=
Id.run <| as.findM? p
@@ -437,24 +461,13 @@ def findRev? {α : Type} (as : Array α) (p : α → Bool) : Option α :=
@[inline]
def findIdx? {α : Type u} (as : Array α) (p : α Bool) : Option Nat :=
let rec loop (i : Nat) (j : Nat) (inv : i + j = as.size) : Option Nat :=
if hlt : j < as.size then
match i, inv with
| 0, inv => by
apply False.elim
rw [Nat.zero_add] at inv
rw [inv] at hlt
exact absurd hlt (Nat.lt_irrefl _)
| i+1, inv =>
if p as[j] then
some j
else
have : i + (j+1) = as.size := by
rw [ inv, Nat.add_comm j 1, Nat.add_assoc]
loop i (j+1) this
else
none
loop as.size 0 rfl
let rec loop (j : Nat) :=
if h : j < as.size then
if p as[j] then some j else loop (j + 1)
else none
termination_by as.size - j
decreasing_by simp_wf; decreasing_trivial_pre_omega
loop 0
def getIdx? [BEq α] (a : Array α) (v : α) : Option Nat :=
a.findIdx? fun a => a == v
@@ -468,7 +481,7 @@ def all (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool
Id.run <| as.allM p start stop
def contains [BEq α] (as : Array α) (a : α) : Bool :=
as.any fun b => a == b
as.any (· == a)
def elem [BEq α] (a : α) (as : Array α) : Bool :=
as.contains a
@@ -487,6 +500,11 @@ def elem [BEq α] (a : α) (as : Array α) : Bool :=
def toList (as : Array α) : List α :=
as.foldr List.cons []
/-- Prepends an `Array α` onto the front of a list. Equivalent to `as.toList ++ l`. -/
@[inline]
def toListAppend (as : Array α) (l : List α) : List α :=
as.foldr List.cons l
instance {α : Type u} [Repr α] : Repr (Array α) where
reprPrec a _ :=
let _ : Std.ToFormat α := repr
@@ -516,6 +534,13 @@ def concatMapM [Monad m] (f : α → m (Array β)) (as : Array α) : m (Array β
def concatMap (f : α Array β) (as : Array α) : Array β :=
as.foldl (init := empty) fun bs a => bs ++ f a
/-- Joins array of array into a single array.
`flatten #[#[a₁, a₂, ⋯], #[b₁, b₂, ⋯], ⋯]` = `#[a₁, a₂, ⋯, b₁, b₂, ⋯]`
-/
def flatten (as : Array (Array α)) : Array α :=
as.foldl (init := empty) fun r a => r ++ a
end Array
export Array (mkArray)
@@ -536,6 +561,7 @@ def isEqvAux (a b : Array α) (hsz : a.size = b.size) (p : αα → Bool) (
else
true
termination_by a.size - i
decreasing_by simp_wf; decreasing_trivial_pre_omega
@[inline] def isEqv (a b : Array α) (p : α α Bool) : Bool :=
if h : a.size = b.size then
@@ -640,6 +666,7 @@ def indexOfAux [BEq α] (a : Array α) (v : α) (i : Nat) : Option (Fin a.size)
else indexOfAux a v (i+1)
else none
termination_by a.size - i
decreasing_by simp_wf; decreasing_trivial_pre_omega
def indexOf? [BEq α] (a : Array α) (v : α) : Option (Fin a.size) :=
indexOfAux a v 0
@@ -682,6 +709,7 @@ def popWhile (p : α → Bool) (as : Array α) : Array α :=
else
as
termination_by as.size
decreasing_by simp_wf; decreasing_trivial_pre_omega
def takeWhile (p : α Bool) (as : Array α) : Array α :=
let rec go (i : Nat) (r : Array α) : Array α :=
@@ -694,35 +722,38 @@ def takeWhile (p : α → Bool) (as : Array α) : Array α :=
else
r
termination_by as.size - i
decreasing_by simp_wf; decreasing_trivial_pre_omega
go 0 #[]
def eraseIdxAux (i : Nat) (a : Array α) : Array α :=
if h : i < a.size then
let idx : Fin a.size := i, h;
let idx1 : Fin a.size := i - 1, by exact Nat.lt_of_le_of_lt (Nat.pred_le i) h;
let a' := a.swap idx idx1
eraseIdxAux (i+1) a'
/-- Remove the element at a given index from an array without bounds checks, using a `Fin` index.
This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`.-/
def feraseIdx (a : Array α) (i : Fin a.size) : Array α :=
if h : i.val + 1 < a.size then
let a' := a.swap i.val + 1, h i
let i' : Fin a'.size := i.val + 1, by simp [a', h]
a'.feraseIdx i'
else
a.pop
termination_by a.size - i
termination_by a.size - i.val
decreasing_by simp_wf; exact Nat.sub_succ_lt_self _ _ i.isLt
def feraseIdx (a : Array α) (i : Fin a.size) : Array α :=
eraseIdxAux (i.val + 1) a
theorem size_feraseIdx (a : Array α) (i : Fin a.size) : (a.feraseIdx i).size = a.size - 1 := by
induction a, i using Array.feraseIdx.induct with
| @case1 a i h a' _ ih =>
unfold feraseIdx
simp [h, a', ih]
| case2 a i h =>
unfold feraseIdx
simp [h]
/-- Remove the element at a given index from an array, or do nothing if the index is out of bounds.
This function takes worst case O(n) time because
it has to backshift all elements at positions greater than `i`.-/
def eraseIdx (a : Array α) (i : Nat) : Array α :=
if i < a.size then eraseIdxAux (i+1) a else a
def eraseIdxSzAux (a : Array α) (i : Nat) (r : Array α) (heq : r.size = a.size) : { r : Array α // r.size = a.size - 1 } :=
if h : i < r.size then
let idx : Fin r.size := i, h;
let idx1 : Fin r.size := i - 1, by exact Nat.lt_of_le_of_lt (Nat.pred_le i) h;
eraseIdxSzAux a (i+1) (r.swap idx idx1) ((size_swap r idx idx1).trans heq)
else
r.pop, (size_pop r).trans (heq rfl)
termination_by r.size - i
def eraseIdx' (a : Array α) (i : Fin a.size) : { r : Array α // r.size = a.size - 1 } :=
eraseIdxSzAux a (i.val + 1) a rfl
if h : i < a.size then a.feraseIdx i, h else a
def erase [BEq α] (as : Array α) (a : α) : Array α :=
match as.indexOf? a with
@@ -739,6 +770,7 @@ def erase [BEq α] (as : Array α) (a : α) : Array α :=
else
as
termination_by j.1
decreasing_by simp_wf; decreasing_trivial_pre_omega
let j := as.size
let as := as.push a
loop as j, size_push .. j.lt_succ_self
@@ -759,11 +791,11 @@ def toArrayLit (a : Array α) (n : Nat) (hsz : a.size = n) : Array α :=
theorem ext' {as bs : Array α} (h : as.data = bs.data) : as = bs := by
cases as; cases bs; simp at h; rw [h]
theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).data = acc.data ++ as := by
@[simp] theorem toArrayAux_eq (as : List α) (acc : Array α) : (as.toArrayAux acc).data = acc.data ++ as := by
induction as generalizing acc <;> simp [*, List.toArrayAux, Array.push, List.append_assoc, List.concat_eq_append]
theorem data_toArray (as : List α) : as.toArray.data = as := by
simp [List.toArray, toArrayAux_eq, Array.mkEmpty]
simp [List.toArray, Array.mkEmpty]
theorem toArrayLit_eq (as : Array α) (n : Nat) (hsz : as.size = n) : as = toArrayLit as n hsz := by
apply ext'
@@ -778,7 +810,7 @@ where
rfl
go (i : Nat) (hi : i as.size) : toListLitAux as n hsz i hi (as.data.drop i) = as.data := by
cases i <;> simp [getLit_eq, List.get_drop_eq_drop, toListLitAux, List.drop, go]
induction i <;> simp [getLit_eq, List.get_drop_eq_drop, toListLitAux, List.drop, *]
def isPrefixOfAux [BEq α] (as bs : Array α) (hle : as.size bs.size) (i : Nat) : Bool :=
if h : i < as.size then
@@ -792,6 +824,7 @@ def isPrefixOfAux [BEq α] (as bs : Array α) (hle : as.size ≤ bs.size) (i : N
else
true
termination_by as.size - i
decreasing_by simp_wf; decreasing_trivial_pre_omega
/-- Return true iff `as` is a prefix of `bs`.
That is, `bs = as ++ t` for some `t : List α`.-/
@@ -813,6 +846,7 @@ private def allDiffAux [BEq α] (as : Array α) (i : Nat) : Bool :=
else
true
termination_by as.size - i
decreasing_by simp_wf; decreasing_trivial_pre_omega
def allDiff [BEq α] (as : Array α) : Bool :=
allDiffAux as 0
@@ -828,6 +862,7 @@ def allDiff [BEq α] (as : Array α) : Bool :=
else
cs
termination_by as.size - i
decreasing_by simp_wf; decreasing_trivial_pre_omega
@[inline] def zipWith (as : Array α) (bs : Array β) (f : α β γ) : Array γ :=
zipWithAux f as bs 0 #[]

View File

@@ -9,7 +9,7 @@ import Init.Data.Nat.Linear
import Init.NotationExtra
theorem Array.of_push_eq_push {as bs : Array α} (h : as.push a = bs.push b) : as = bs a = b := by
simp [push] at h
simp only [push, mk.injEq] at h
have h₁, h₂ := List.of_concat_eq_concat h
cases as; cases bs
simp_all
@@ -48,6 +48,7 @@ where
let b f as[i]
go (i+1) acc.val.push b, by simp [acc.property] hlt
termination_by as.size - i
decreasing_by decreasing_trivial_pre_omega
@[inline] private unsafe def mapMonoMImp [Monad m] (as : Array α) (f : α m α) : m (Array α) :=
go 0 as

View File

@@ -5,7 +5,7 @@ Authors: Leonardo de Moura
-/
prelude
import Init.Data.Array.Basic
import Init.Classical
import Init.ByCases
namespace Array
@@ -21,22 +21,25 @@ theorem eq_of_isEqvAux [DecidableEq α] (a b : Array α) (hsz : a.size = b.size)
subst heq
exact absurd (Nat.lt_of_lt_of_le high low) (Nat.lt_irrefl j)
termination_by a.size - i
decreasing_by decreasing_trivial_pre_omega
theorem eq_of_isEqv [DecidableEq α] (a b : Array α) : Array.isEqv a b (fun x y => x = y) a = b := by
simp [Array.isEqv]
split
case inr => intro; contradiction
case inl hsz =>
next hsz =>
intro h
have aux := eq_of_isEqvAux a b hsz 0 (Nat.zero_le ..) h
exact ext a b hsz fun i h _ => aux i (Nat.zero_le ..) _
next => intro; contradiction
theorem isEqvAux_self [DecidableEq α] (a : Array α) (i : Nat) : Array.isEqvAux a a rfl (fun x y => x = y) i = true := by
unfold Array.isEqvAux
split
case inl h => simp [h, isEqvAux_self a (i+1)]
case inr h => simp [h]
next h => simp [h, isEqvAux_self a (i+1)]
next h => simp [h]
termination_by a.size - i
decreasing_by decreasing_trivial_pre_omega
theorem isEqv_self [DecidableEq α] (a : Array α) : Array.isEqv a a (fun x y => x = y) = true := by
simp [isEqv, isEqvAux_self]

File diff suppressed because it is too large Load Diff

View File

@@ -8,16 +8,6 @@ import Init.Data.Array.Basic
import Init.Data.Nat.Linear
import Init.Data.List.BasicAux
theorem List.sizeOf_get_lt [SizeOf α] (as : List α) (i : Fin as.length) : sizeOf (as.get i) < sizeOf as := by
match as, i with
| [], i => apply Fin.elim0 i
| a::as, 0, _ => simp_arith [get]
| a::as, i+1, h =>
simp [get]
have h : i < as.length := Nat.lt_of_succ_lt_succ h
have ih := sizeOf_get_lt as i, h
exact Nat.lt_of_lt_of_le ih (Nat.le_add_left ..)
namespace Array
/-- `a ∈ as` is a predicate which asserts that `a` is in the array `as`. -/
@@ -29,10 +19,6 @@ structure Mem (a : α) (as : Array α) : Prop where
instance : Membership α (Array α) where
mem a as := Mem a as
theorem sizeOf_get_lt [SizeOf α] (as : Array α) (i : Fin as.size) : sizeOf (as.get i) < sizeOf as := by
cases as with | _ as =>
exact Nat.lt_trans (List.sizeOf_get_lt as i) (by simp_arith)
theorem sizeOf_lt_of_mem [SizeOf α] {as : Array α} (h : a as) : sizeOf a < sizeOf as := by
cases as with | _ as =>
exact Nat.lt_trans (List.sizeOf_lt_of_mem h.val) (by simp_arith)
@@ -41,13 +27,20 @@ theorem sizeOf_lt_of_mem [SizeOf α] {as : Array α} (h : a ∈ as) : sizeOf a <
cases as with | _ as =>
exact Nat.lt_trans (List.sizeOf_get ..) (by simp_arith)
@[simp] theorem sizeOf_getElem [SizeOf α] (as : Array α) (i : Nat) (h : i < as.size) :
sizeOf (as[i]'h) < sizeOf as := sizeOf_get _ _
/-- This tactic, added to the `decreasing_trivial` toolbox, proves that
`sizeOf arr[i] < sizeOf arr`, which is useful for well founded recursions
over a nested inductive like `inductive T | mk : Array T → T`. -/
macro "array_get_dec" : tactic =>
`(tactic| first
| apply sizeOf_get
| apply Nat.lt_trans (sizeOf_get ..); simp_arith)
-- subsumed by simp
-- | with_reducible apply sizeOf_get
-- | with_reducible apply sizeOf_getElem
| (with_reducible apply Nat.lt_trans (sizeOf_get ..)); simp_arith
| (with_reducible apply Nat.lt_trans (sizeOf_getElem ..)); simp_arith
)
macro_rules | `(tactic| decreasing_trivial) => `(tactic| array_get_dec)
@@ -57,9 +50,10 @@ provided that `a ∈ arr` which is useful for well founded recursions over a nes
-- NB: This is analogue to tactic `sizeOf_list_dec`
macro "array_mem_dec" : tactic =>
`(tactic| first
| apply Array.sizeOf_lt_of_mem; assumption; done
| apply Nat.lt_trans (Array.sizeOf_lt_of_mem ?h)
case' h => assumption
| with_reducible apply Array.sizeOf_lt_of_mem; assumption; done
| with_reducible
apply Nat.lt_trans (Array.sizeOf_lt_of_mem ?h)
case' h => assumption
simp_arith)
macro_rules | `(tactic| decreasing_trivial) => `(tactic| array_mem_dec)

View File

@@ -10,7 +10,7 @@ namespace Array
-- TODO: remove the [Inhabited α] parameters as soon as we have the tactic framework for automating proof generation and using Array.fget
def qpartition (as : Array α) (lt : α α Bool) (lo hi : Nat) : Nat × Array α :=
if h : as.size = 0 then (0, as) else have : Inhabited α := as[0]'(by revert h; cases as.size <;> simp [Nat.zero_lt_succ]) -- TODO: remove
if h : as.size = 0 then (0, as) else have : Inhabited α := as[0]'(by revert h; cases as.size <;> simp) -- TODO: remove
let mid := (lo + hi) / 2
let as := if lt (as.get! mid) (as.get! lo) then as.swap! lo mid else as
let as := if lt (as.get! hi) (as.get! lo) then as.swap! lo hi else as
@@ -27,6 +27,7 @@ def qpartition (as : Array α) (lt : αα → Bool) (lo hi : Nat) : Nat ×
let as := as.swap! i hi
(i, as)
termination_by hi - j
decreasing_by all_goals simp_wf; decreasing_trivial_pre_omega
loop as lo lo
@[inline] partial def qsort (as : Array α) (lt : α α Bool) (low := 0) (high := as.size - 1) : Array α :=

View File

@@ -9,29 +9,46 @@ import Init.Data.Array.Basic
universe u v w
structure Subarray (α : Type u) where
as : Array α
array : Array α
start : Nat
stop : Nat
h₁ : start stop
h₂ : stop as.size
start_le_stop : start stop
stop_le_array_size : stop array.size
@[deprecated Subarray.array (since := "2024-04-13")]
abbrev Subarray.as (s : Subarray α) : Array α := s.array
@[deprecated Subarray.start_le_stop (since := "2024-04-13")]
theorem Subarray.h₁ (s : Subarray α) : s.start s.stop := s.start_le_stop
@[deprecated Subarray.stop_le_array_size (since := "2024-04-13")]
theorem Subarray.h₂ (s : Subarray α) : s.stop s.array.size := s.stop_le_array_size
namespace Subarray
def size (s : Subarray α) : Nat :=
s.stop - s.start
theorem size_le_array_size {s : Subarray α} : s.size s.array.size := by
let {array, start, stop, start_le_stop, stop_le_array_size} := s
simp [size]
apply Nat.le_trans (Nat.sub_le stop start)
assumption
def get (s : Subarray α) (i : Fin s.size) : α :=
have : s.start + i.val < s.as.size := by
apply Nat.lt_of_lt_of_le _ s.h₂
have : s.start + i.val < s.array.size := by
apply Nat.lt_of_lt_of_le _ s.stop_le_array_size
have := i.isLt
simp [size] at this
rw [Nat.add_comm]
exact Nat.add_lt_of_lt_sub this
s.as[s.start + i.val]
s.array[s.start + i.val]
instance : GetElem (Subarray α) Nat α fun xs i => i < xs.size where
getElem xs i h := xs.get i, h
instance : LawfulGetElem (Subarray α) Nat α fun xs i => i < xs.size where
@[inline] def getD (s : Subarray α) (i : Nat) (v₀ : α) : α :=
if h : i < s.size then s.get i, h else v₀
@@ -40,7 +57,7 @@ abbrev get! [Inhabited α] (s : Subarray α) (i : Nat) : α :=
def popFront (s : Subarray α) : Subarray α :=
if h : s.start < s.stop then
{ s with start := s.start + 1, h₁ := Nat.le_of_lt_succ (Nat.add_lt_add_right h 1) }
{ s with start := s.start + 1, start_le_stop := Nat.le_of_lt_succ (Nat.add_lt_add_right h 1) }
else
s
@@ -48,7 +65,7 @@ def popFront (s : Subarray α) : Subarray α :=
let sz := USize.ofNat s.stop
let rec @[specialize] loop (i : USize) (b : β) : m β := do
if i < sz then
let a := s.as.uget i lcProof
let a := s.array.uget i lcProof
match ( f a b) with
| ForInStep.done b => pure b
| ForInStep.yield b => loop (i+1) b
@@ -66,27 +83,27 @@ instance : ForIn m (Subarray α) α where
@[inline]
def foldlM {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : β α m β) (init : β) (as : Subarray α) : m β :=
as.as.foldlM f (init := init) (start := as.start) (stop := as.stop)
as.array.foldlM f (init := init) (start := as.start) (stop := as.stop)
@[inline]
def foldrM {α : Type u} {β : Type v} {m : Type v Type w} [Monad m] (f : α β m β) (init : β) (as : Subarray α) : m β :=
as.as.foldrM f (init := init) (start := as.stop) (stop := as.start)
as.array.foldrM f (init := init) (start := as.stop) (stop := as.start)
@[inline]
def anyM {α : Type u} {m : Type Type w} [Monad m] (p : α m Bool) (as : Subarray α) : m Bool :=
as.as.anyM p (start := as.start) (stop := as.stop)
as.array.anyM p (start := as.start) (stop := as.stop)
@[inline]
def allM {α : Type u} {m : Type Type w} [Monad m] (p : α m Bool) (as : Subarray α) : m Bool :=
as.as.allM p (start := as.start) (stop := as.stop)
as.array.allM p (start := as.start) (stop := as.stop)
@[inline]
def forM {α : Type u} {m : Type v Type w} [Monad m] (f : α m PUnit) (as : Subarray α) : m PUnit :=
as.as.forM f (start := as.start) (stop := as.stop)
as.array.forM f (start := as.start) (stop := as.stop)
@[inline]
def forRevM {α : Type u} {m : Type v Type w} [Monad m] (f : α m PUnit) (as : Subarray α) : m PUnit :=
as.as.forRevM f (start := as.stop) (stop := as.start)
as.array.forRevM f (start := as.stop) (stop := as.start)
@[inline]
def foldl {α : Type u} {β : Type v} (f : β α β) (init : β) (as : Subarray α) : β :=
@@ -133,16 +150,27 @@ variable {α : Type u}
def toSubarray (as : Array α) (start : Nat := 0) (stop : Nat := as.size) : Subarray α :=
if h₂ : stop as.size then
if h₁ : start stop then
{ as := as, start := start, stop := stop, h₁ := h₁, h₂ := h₂ }
else
{ as := as, start := stop, stop := stop, h₁ := Nat.le_refl _, h₂ := h₂ }
if h₁ : start stop then
{ array := as, start := start, stop := stop,
start_le_stop := h₁, stop_le_array_size := h₂ }
else
{ array := as, start := stop, stop := stop,
start_le_stop := Nat.le_refl _, stop_le_array_size := h₂ }
else
if h₁ : start as.size then
{ as := as, start := start, stop := as.size, h₁ := h₁, h₂ := Nat.le_refl _ }
else
{ as := as, start := as.size, stop := as.size, h₁ := Nat.le_refl _, h₂ := Nat.le_refl _ }
if h₁ : start as.size then
{ array := as,
start := start,
stop := as.size,
start_le_stop := h₁,
stop_le_array_size := Nat.le_refl _ }
else
{ array := as,
start := as.size,
stop := as.size,
start_le_stop := Nat.le_refl _,
stop_le_array_size := Nat.le_refl _ }
@[coe]
def ofSubarray (s : Subarray α) : Array α := Id.run do
let mut as := mkEmpty (s.stop - s.start)
for a in s do

View File

@@ -0,0 +1,71 @@
/-
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: David Thrane Christiansen
-/
prelude
import Init.Data.Array.Basic
import Init.Data.Array.Subarray
import Init.Omega
/-
This module contains splitting operations on subarrays that crucially rely on `omega` for proof
automation. Placing them in another module breaks an import cycle, because `omega` itself uses the
array library.
-/
namespace Subarray
/--
Splits a subarray into two parts.
-/
def split (s : Subarray α) (i : Fin s.size.succ) : (Subarray α × Subarray α) :=
let i', isLt := i
have := s.start_le_stop
have := s.stop_le_array_size
have : i' s.stop - s.start := Nat.lt_succ.mp isLt
have : s.start + i' s.stop := by omega
have : s.start + i' s.array.size := by omega
have : s.start + i' s.stop := by
simp only [size] at isLt
omega
let pre := {s with
stop := s.start + i',
start_le_stop := by omega,
stop_le_array_size := by assumption
}
let post := {s with
start := s.start + i'
start_le_stop := by assumption
}
(pre, post)
/--
Removes the first `i` elements of the subarray. If there are `i` or fewer elements, the resulting
subarray is empty.
-/
def drop (arr : Subarray α) (i : Nat) : Subarray α where
array := arr.array
start := min (arr.start + i) arr.stop
stop := arr.stop
start_le_stop := by
rw [Nat.min_def]
split <;> simp only [Nat.le_refl, *]
stop_le_array_size := arr.stop_le_array_size
/--
Keeps only the first `i` elements of the subarray. If there are `i` or fewer elements, the resulting
subarray is empty.
-/
def take (arr : Subarray α) (i : Nat) : Subarray α where
array := arr.array
start := arr.start
stop := min (arr.start + i) arr.stop
start_le_stop := by
have := arr.start_le_stop
rw [Nat.min_def]
split <;> omega
stop_le_array_size := by
have := arr.stop_le_array_size
rw [Nat.min_def]
split <;> omega

10
src/Init/Data/BitVec.lean Normal file
View File

@@ -0,0 +1,10 @@
/-
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Scott Morrison
-/
prelude
import Init.Data.BitVec.Basic
import Init.Data.BitVec.Bitblast
import Init.Data.BitVec.Folds
import Init.Data.BitVec.Lemmas

View File

@@ -0,0 +1,652 @@
/-
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joe Hendrix, Wojciech Nawrocki, Leonardo de Moura, Mario Carneiro, Alex Keizer, Harun Khan, Abdalrhman M Mohamed
-/
prelude
import Init.Data.Fin.Basic
import Init.Data.Nat.Bitwise.Lemmas
import Init.Data.Nat.Power2
import Init.Data.Int.Bitwise
/-!
We define bitvectors. We choose the `Fin` representation over others for its relative efficiency
(Lean has special support for `Nat`), alignment with `UIntXY` types which are also represented
with `Fin`, and the fact that bitwise operations on `Fin` are already defined. Some other possible
representations are `List Bool`, `{ l : List Bool // l.length = w }`, `Fin w → Bool`.
We define many of the bitvector operations from the
[`QF_BV` logic](https://smtlib.cs.uiowa.edu/logics-all.shtml#QF_BV).
of SMT-LIBv2.
-/
/--
A bitvector of the specified width.
This is represented as the underlying `Nat` number in both the runtime
and the kernel, inheriting all the special support for `Nat`.
-/
structure BitVec (w : Nat) where
/-- Construct a `BitVec w` from a number less than `2^w`.
O(1), because we use `Fin` as the internal representation of a bitvector. -/
ofFin ::
/-- Interpret a bitvector as a number less than `2^w`.
O(1), because we use `Fin` as the internal representation of a bitvector. -/
toFin : Fin (2^w)
@[deprecated (since := "2024-04-12")]
protected abbrev Std.BitVec := _root_.BitVec
-- We manually derive the `DecidableEq` instances for `BitVec` because
-- we want to have builtin support for bit-vector literals, and we
-- need a name for this function to implement `canUnfoldAtMatcher` at `WHNF.lean`.
def BitVec.decEq (a b : BitVec n) : Decidable (a = b) :=
match a, b with
| n, m =>
if h : n = m then
isTrue (h rfl)
else
isFalse (fun h' => BitVec.noConfusion h' (fun h' => absurd h' h))
instance : DecidableEq (BitVec n) := BitVec.decEq
namespace BitVec
section Nat
/-- The `BitVec` with value `i`, given a proof that `i < 2^n`. -/
@[match_pattern]
protected def ofNatLt {n : Nat} (i : Nat) (p : i < 2^n) : BitVec n where
toFin := i, p
/-- The `BitVec` with value `i mod 2^n`. -/
@[match_pattern]
protected def ofNat (n : Nat) (i : Nat) : BitVec n where
toFin := Fin.ofNat' i (Nat.two_pow_pos n)
instance instOfNat : OfNat (BitVec n) i where ofNat := .ofNat n i
instance natCastInst : NatCast (BitVec w) := BitVec.ofNat w
/-- Given a bitvector `a`, return the underlying `Nat`. This is O(1) because `BitVec` is a
(zero-cost) wrapper around a `Nat`. -/
protected def toNat (a : BitVec n) : Nat := a.toFin.val
/-- Return the bound in terms of toNat. -/
theorem isLt (x : BitVec w) : x.toNat < 2^w := x.toFin.isLt
@[deprecated isLt (since := "2024-03-12")]
theorem toNat_lt (x : BitVec n) : x.toNat < 2^n := x.isLt
/-- Theorem for normalizing the bit vector literal representation. -/
-- TODO: This needs more usage data to assess which direction the simp should go.
@[simp, bv_toNat] theorem ofNat_eq_ofNat : @OfNat.ofNat (BitVec n) i _ = .ofNat n i := rfl
-- Note. Mathlib would like this to go the other direction.
@[simp] theorem natCast_eq_ofNat (w x : Nat) : @Nat.cast (BitVec w) _ x = .ofNat w x := rfl
end Nat
section subsingleton
/-- All empty bitvectors are equal -/
instance : Subsingleton (BitVec 0) where
allEq := by intro 0, _ 0, _; rfl
/-- The empty bitvector -/
abbrev nil : BitVec 0 := 0
/-- Every bitvector of length 0 is equal to `nil`, i.e., there is only one empty bitvector -/
theorem eq_nil (x : BitVec 0) : x = nil := Subsingleton.allEq ..
end subsingleton
section zero_allOnes
/-- Return a bitvector `0` of size `n`. This is the bitvector with all zero bits. -/
protected def zero (n : Nat) : BitVec n := .ofNatLt 0 (Nat.two_pow_pos n)
instance : Inhabited (BitVec n) where default := .zero n
/-- Bit vector of size `n` where all bits are `1`s -/
def allOnes (n : Nat) : BitVec n :=
.ofNatLt (2^n - 1) (Nat.le_of_eq (Nat.sub_add_cancel (Nat.two_pow_pos n)))
end zero_allOnes
section getXsb
/-- Return the `i`-th least significant bit or `false` if `i ≥ w`. -/
@[inline] def getLsb (x : BitVec w) (i : Nat) : Bool := x.toNat.testBit i
/-- Return the `i`-th most significant bit or `false` if `i ≥ w`. -/
@[inline] def getMsb (x : BitVec w) (i : Nat) : Bool := i < w && getLsb x (w-1-i)
/-- Return most-significant bit in bitvector. -/
@[inline] protected def msb (a : BitVec n) : Bool := getMsb a 0
end getXsb
section Int
/-- Interpret the bitvector as an integer stored in two's complement form. -/
protected def toInt (a : BitVec n) : Int :=
if 2 * a.toNat < 2^n then
a.toNat
else
(a.toNat : Int) - (2^n : Nat)
/-- The `BitVec` with value `(2^n + (i mod 2^n)) mod 2^n`. -/
protected def ofInt (n : Nat) (i : Int) : BitVec n := .ofNatLt (i % (Int.ofNat (2^n))).toNat (by
apply (Int.toNat_lt _).mpr
· apply Int.emod_lt_of_pos
exact Int.ofNat_pos.mpr (Nat.two_pow_pos _)
· apply Int.emod_nonneg
intro eq
apply Nat.ne_of_gt (Nat.two_pow_pos n)
exact Int.ofNat_inj.mp eq)
instance : IntCast (BitVec w) := BitVec.ofInt w
end Int
section Syntax
/-- Notation for bit vector literals. `i#n` is a shorthand for `BitVec.ofNat n i`. -/
syntax:max num noWs "#" noWs term:max : term
macro_rules | `($i:num#$n) => `(BitVec.ofNat $n $i)
/-- Unexpander for bit vector literals. -/
@[app_unexpander BitVec.ofNat] def unexpandBitVecOfNat : Lean.PrettyPrinter.Unexpander
| `($(_) $n $i:num) => `($i:num#$n)
| _ => throw ()
/-- Notation for bit vector literals without truncation. `i#'lt` is a shorthand for `BitVec.ofNatLt i lt`. -/
scoped syntax:max term:max noWs "#'" noWs term:max : term
macro_rules | `($i#'$p) => `(BitVec.ofNatLt $i $p)
/-- Unexpander for bit vector literals without truncation. -/
@[app_unexpander BitVec.ofNatLt] def unexpandBitVecOfNatLt : Lean.PrettyPrinter.Unexpander
| `($(_) $i $p) => `($i#'$p)
| _ => throw ()
end Syntax
section repr_toString
/-- Convert bitvector into a fixed-width hex number. -/
protected def toHex {n : Nat} (x : BitVec n) : String :=
let s := (Nat.toDigits 16 x.toNat).asString
let t := (List.replicate ((n+3) / 4 - s.length) '0').asString
t ++ s
instance : Repr (BitVec n) where reprPrec a _ := "0x" ++ (a.toHex : Std.Format) ++ "#" ++ repr n
instance : ToString (BitVec n) where toString a := toString (repr a)
end repr_toString
section arithmetic
/--
Addition for bit vectors. This can be interpreted as either signed or unsigned addition
modulo `2^n`.
SMT-Lib name: `bvadd`.
-/
protected def add (x y : BitVec n) : BitVec n := .ofNat n (x.toNat + y.toNat)
instance : Add (BitVec n) := BitVec.add
/--
Subtraction for bit vectors. This can be interpreted as either signed or unsigned subtraction
modulo `2^n`.
-/
protected def sub (x y : BitVec n) : BitVec n := .ofNat n ((2^n - y.toNat) + x.toNat)
instance : Sub (BitVec n) := BitVec.sub
/--
Negation for bit vectors. This can be interpreted as either signed or unsigned negation
modulo `2^n`.
SMT-Lib name: `bvneg`.
-/
protected def neg (x : BitVec n) : BitVec n := .ofNat n (2^n - x.toNat)
instance : Neg (BitVec n) := .neg
/--
Return the absolute value of a signed bitvector.
-/
protected def abs (s : BitVec n) : BitVec n := if s.msb then .neg s else s
/--
Multiplication for bit vectors. This can be interpreted as either signed or unsigned negation
modulo `2^n`.
SMT-Lib name: `bvmul`.
-/
protected def mul (x y : BitVec n) : BitVec n := BitVec.ofNat n (x.toNat * y.toNat)
instance : Mul (BitVec n) := .mul
/--
Unsigned division for bit vectors using the Lean convention where division by zero returns zero.
-/
def udiv (x y : BitVec n) : BitVec n :=
(x.toNat / y.toNat)#'(Nat.lt_of_le_of_lt (Nat.div_le_self _ _) x.isLt)
instance : Div (BitVec n) := .udiv
/--
Unsigned modulo for bit vectors.
SMT-Lib name: `bvurem`.
-/
def umod (x y : BitVec n) : BitVec n :=
(x.toNat % y.toNat)#'(Nat.lt_of_le_of_lt (Nat.mod_le _ _) x.isLt)
instance : Mod (BitVec n) := .umod
/--
Unsigned division for bit vectors using the
[SMT-Lib convention](http://smtlib.cs.uiowa.edu/theories-FixedSizeBitVectors.shtml)
where division by zero returns the `allOnes` bitvector.
SMT-Lib name: `bvudiv`.
-/
def smtUDiv (x y : BitVec n) : BitVec n := if y = 0 then allOnes n else udiv x y
/--
Signed t-division for bit vectors using the Lean convention where division
by zero returns zero.
```lean
sdiv 7#4 2 = 3#4
sdiv (-9#4) 2 = -4#4
sdiv 5#4 -2 = -2#4
sdiv (-7#4) (-2) = 3#4
```
-/
def sdiv (s t : BitVec n) : BitVec n :=
match s.msb, t.msb with
| false, false => udiv s t
| false, true => .neg (udiv s (.neg t))
| true, false => .neg (udiv (.neg s) t)
| true, true => udiv (.neg s) (.neg t)
/--
Signed division for bit vectors using SMTLIB rules for division by zero.
Specifically, `smtSDiv x 0 = if x >= 0 then -1 else 1`
SMT-Lib name: `bvsdiv`.
-/
def smtSDiv (s t : BitVec n) : BitVec n :=
match s.msb, t.msb with
| false, false => smtUDiv s t
| false, true => .neg (smtUDiv s (.neg t))
| true, false => .neg (smtUDiv (.neg s) t)
| true, true => smtUDiv (.neg s) (.neg t)
/--
Remainder for signed division rounding to zero.
SMT_Lib name: `bvsrem`.
-/
def srem (s t : BitVec n) : BitVec n :=
match s.msb, t.msb with
| false, false => umod s t
| false, true => umod s (.neg t)
| true, false => .neg (umod (.neg s) t)
| true, true => .neg (umod (.neg s) (.neg t))
/--
Remainder for signed division rounded to negative infinity.
SMT_Lib name: `bvsmod`.
-/
def smod (s t : BitVec m) : BitVec m :=
match s.msb, t.msb with
| false, false => umod s t
| false, true =>
let u := umod s (.neg t)
(if u = .zero m then u else .add u t)
| true, false =>
let u := umod (.neg s) t
(if u = .zero m then u else .sub t u)
| true, true => .neg (umod (.neg s) (.neg t))
end arithmetic
section bool
/-- Turn a `Bool` into a bitvector of length `1` -/
def ofBool (b : Bool) : BitVec 1 := cond b 1 0
@[simp] theorem ofBool_false : ofBool false = 0 := by trivial
@[simp] theorem ofBool_true : ofBool true = 1 := by trivial
/-- Fills a bitvector with `w` copies of the bit `b`. -/
def fill (w : Nat) (b : Bool) : BitVec w := bif b then -1 else 0
end bool
section relations
/--
Unsigned less-than for bit vectors.
SMT-Lib name: `bvult`.
-/
protected def ult (x y : BitVec n) : Bool := x.toNat < y.toNat
instance : LT (BitVec n) where lt := (·.toNat < ·.toNat)
instance (x y : BitVec n) : Decidable (x < y) :=
inferInstanceAs (Decidable (x.toNat < y.toNat))
/--
Unsigned less-than-or-equal-to for bit vectors.
SMT-Lib name: `bvule`.
-/
protected def ule (x y : BitVec n) : Bool := x.toNat y.toNat
instance : LE (BitVec n) where le := (·.toNat ·.toNat)
instance (x y : BitVec n) : Decidable (x y) :=
inferInstanceAs (Decidable (x.toNat y.toNat))
/--
Signed less-than for bit vectors.
```lean
BitVec.slt 6#4 7 = true
BitVec.slt 7#4 8 = false
```
SMT-Lib name: `bvslt`.
-/
protected def slt (x y : BitVec n) : Bool := x.toInt < y.toInt
/--
Signed less-than-or-equal-to for bit vectors.
SMT-Lib name: `bvsle`.
-/
protected def sle (x y : BitVec n) : Bool := x.toInt y.toInt
end relations
section cast
/-- `cast eq i` embeds `i` into an equal `BitVec` type. -/
@[inline] def cast (eq : n = m) (i : BitVec n) : BitVec m := .ofNatLt i.toNat (eq i.isLt)
@[simp] theorem cast_ofNat {n m : Nat} (h : n = m) (x : Nat) :
cast h (BitVec.ofNat n x) = BitVec.ofNat m x := by
subst h; rfl
@[simp] theorem cast_cast {n m k : Nat} (h₁ : n = m) (h₂ : m = k) (x : BitVec n) :
cast h₂ (cast h₁ x) = cast (h₁ h₂) x :=
rfl
@[simp] theorem cast_eq {n : Nat} (h : n = n) (x : BitVec n) : cast h x = x := rfl
/--
Extraction of bits `start` to `start + len - 1` from a bit vector of size `n` to yield a
new bitvector of size `len`. If `start + len > n`, then the vector will be zero-padded in the
high bits.
-/
def extractLsb' (start len : Nat) (a : BitVec n) : BitVec len := .ofNat _ (a.toNat >>> start)
/--
Extraction of bits `hi` (inclusive) down to `lo` (inclusive) from a bit vector of size `n` to
yield a new bitvector of size `hi - lo + 1`.
SMT-Lib name: `extract`.
-/
def extractLsb (hi lo : Nat) (a : BitVec n) : BitVec (hi - lo + 1) := extractLsb' lo _ a
/--
A version of `zeroExtend` that requires a proof, but is a noop.
-/
def zeroExtend' {n w : Nat} (le : n w) (x : BitVec n) : BitVec w :=
x.toNat#'(by
apply Nat.lt_of_lt_of_le x.isLt
exact Nat.pow_le_pow_of_le_right (by trivial) le)
/--
`shiftLeftZeroExtend x n` returns `zeroExtend (w+n) x <<< n` without
needing to compute `x % 2^(2+n)`.
-/
def shiftLeftZeroExtend (msbs : BitVec w) (m : Nat) : BitVec (w+m) :=
let shiftLeftLt {x : Nat} (p : x < 2^w) (m : Nat) : x <<< m < 2^(w+m) := by
simp [Nat.shiftLeft_eq, Nat.pow_add]
apply Nat.mul_lt_mul_of_pos_right p
exact (Nat.two_pow_pos m)
(msbs.toNat <<< m)#'(shiftLeftLt msbs.isLt m)
/--
Zero extend vector `x` of length `w` by adding zeros in the high bits until it has length `v`.
If `v < w` then it truncates the high bits instead.
SMT-Lib name: `zero_extend`.
-/
def zeroExtend (v : Nat) (x : BitVec w) : BitVec v :=
if h : w v then
zeroExtend' h x
else
.ofNat v x.toNat
/--
Truncate the high bits of bitvector `x` of length `w`, resulting in a vector of length `v`.
If `v > w` then it zero-extends the vector instead.
-/
abbrev truncate := @zeroExtend
/--
Sign extend a vector of length `w`, extending with `i` additional copies of the most significant
bit in `x`. If `x` is an empty vector, then the sign is treated as zero.
SMT-Lib name: `sign_extend`.
-/
def signExtend (v : Nat) (x : BitVec w) : BitVec v := .ofInt v x.toInt
end cast
section bitwise
/--
Bitwise AND for bit vectors.
```lean
0b1010#4 &&& 0b0110#4 = 0b0010#4
```
SMT-Lib name: `bvand`.
-/
protected def and (x y : BitVec n) : BitVec n :=
(x.toNat &&& y.toNat)#'(Nat.and_lt_two_pow x.toNat y.isLt)
instance : AndOp (BitVec w) := .and
/--
Bitwise OR for bit vectors.
```lean
0b1010#4 ||| 0b0110#4 = 0b1110#4
```
SMT-Lib name: `bvor`.
-/
protected def or (x y : BitVec n) : BitVec n :=
(x.toNat ||| y.toNat)#'(Nat.or_lt_two_pow x.isLt y.isLt)
instance : OrOp (BitVec w) := .or
/--
Bitwise XOR for bit vectors.
```lean
0b1010#4 ^^^ 0b0110#4 = 0b1100#4
```
SMT-Lib name: `bvxor`.
-/
protected def xor (x y : BitVec n) : BitVec n :=
(x.toNat ^^^ y.toNat)#'(Nat.xor_lt_two_pow x.isLt y.isLt)
instance : Xor (BitVec w) := .xor
/--
Bitwise NOT for bit vectors.
```lean
~~~(0b0101#4) == 0b1010
```
SMT-Lib name: `bvnot`.
-/
protected def not (x : BitVec n) : BitVec n := allOnes n ^^^ x
instance : Complement (BitVec w) := .not
/--
Left shift for bit vectors. The low bits are filled with zeros. As a numeric operation, this is
equivalent to `a * 2^s`, modulo `2^n`.
SMT-Lib name: `bvshl` except this operator uses a `Nat` shift value.
-/
protected def shiftLeft (a : BitVec n) (s : Nat) : BitVec n := BitVec.ofNat n (a.toNat <<< s)
instance : HShiftLeft (BitVec w) Nat (BitVec w) := .shiftLeft
/--
(Logical) right shift for bit vectors. The high bits are filled with zeros.
As a numeric operation, this is equivalent to `a / 2^s`, rounding down.
SMT-Lib name: `bvlshr` except this operator uses a `Nat` shift value.
-/
def ushiftRight (a : BitVec n) (s : Nat) : BitVec n :=
(a.toNat >>> s)#'(by
let a, lt := a
simp only [BitVec.toNat, Nat.shiftRight_eq_div_pow, Nat.div_lt_iff_lt_mul (Nat.two_pow_pos s)]
rw [Nat.mul_one a]
exact Nat.mul_lt_mul_of_lt_of_le' lt (Nat.two_pow_pos s) (Nat.le_refl 1))
instance : HShiftRight (BitVec w) Nat (BitVec w) := .ushiftRight
/--
Arithmetic right shift for bit vectors. The high bits are filled with the
most-significant bit.
As a numeric operation, this is equivalent to `a.toInt >>> s`.
SMT-Lib name: `bvashr` except this operator uses a `Nat` shift value.
-/
def sshiftRight (a : BitVec n) (s : Nat) : BitVec n := .ofInt n (a.toInt >>> s)
instance {n} : HShiftLeft (BitVec m) (BitVec n) (BitVec m) := fun x y => x <<< y.toNat
instance {n} : HShiftRight (BitVec m) (BitVec n) (BitVec m) := fun x y => x >>> y.toNat
/-- Auxiliary function for `rotateLeft`, which does not take into account the case where
the rotation amount is greater than the bitvector width. -/
def rotateLeftAux (x : BitVec w) (n : Nat) : BitVec w :=
x <<< n ||| x >>> (w - n)
/--
Rotate left for bit vectors. All the bits of `x` are shifted to higher positions, with the top `n`
bits wrapping around to fill the low bits.
```lean
rotateLeft 0b0011#4 3 = 0b1001
```
SMT-Lib name: `rotate_left` except this operator uses a `Nat` shift amount.
-/
def rotateLeft (x : BitVec w) (n : Nat) : BitVec w := rotateLeftAux x (n % w)
/--
Auxiliary function for `rotateRight`, which does not take into account the case where
the rotation amount is greater than the bitvector width.
-/
def rotateRightAux (x : BitVec w) (n : Nat) : BitVec w :=
x >>> n ||| x <<< (w - n)
/--
Rotate right for bit vectors. All the bits of `x` are shifted to lower positions, with the
bottom `n` bits wrapping around to fill the high bits.
```lean
rotateRight 0b01001#5 1 = 0b10100
```
SMT-Lib name: `rotate_right` except this operator uses a `Nat` shift amount.
-/
def rotateRight (x : BitVec w) (n : Nat) : BitVec w := rotateRightAux x (n % w)
/--
Concatenation of bitvectors. This uses the "big endian" convention that the more significant
input is on the left, so `0xAB#8 ++ 0xCD#8 = 0xABCD#16`.
SMT-Lib name: `concat`.
-/
def append (msbs : BitVec n) (lsbs : BitVec m) : BitVec (n+m) :=
shiftLeftZeroExtend msbs m ||| zeroExtend' (Nat.le_add_left m n) lsbs
instance : HAppend (BitVec w) (BitVec v) (BitVec (w + v)) := .append
-- TODO: write this using multiplication
/-- `replicate i x` concatenates `i` copies of `x` into a new vector of length `w*i`. -/
def replicate : (i : Nat) BitVec w BitVec (w*i)
| 0, _ => 0
| n+1, x =>
have hEq : w + w*n = w*(n + 1) := by
rw [Nat.mul_add, Nat.add_comm, Nat.mul_one]
hEq (x ++ replicate n x)
/-!
### Cons and Concat
We give special names to the operations of adding a single bit to either end of a bitvector.
We follow the precedent of `Vector.cons`/`Vector.concat` both for the name, and for the decision
to have the resulting size be `n + 1` for both operations (rather than `1 + n`, which would be the
result of appending a single bit to the front in the naive implementation).
-/
/-- Append a single bit to the end of a bitvector, using big endian order (see `append`).
That is, the new bit is the least significant bit. -/
def concat {n} (msbs : BitVec n) (lsb : Bool) : BitVec (n+1) := msbs ++ (ofBool lsb)
/-- Prepend a single bit to the front of a bitvector, using big endian order (see `append`).
That is, the new bit is the most significant bit. -/
def cons {n} (msb : Bool) (lsbs : BitVec n) : BitVec (n+1) :=
((ofBool msb) ++ lsbs).cast (Nat.add_comm ..)
theorem append_ofBool (msbs : BitVec w) (lsb : Bool) :
msbs ++ ofBool lsb = concat msbs lsb :=
rfl
theorem ofBool_append (msb : Bool) (lsbs : BitVec w) :
ofBool msb ++ lsbs = (cons msb lsbs).cast (Nat.add_comm ..) :=
rfl
/--
`twoPow w i` is the bitvector `2^i` if `i < w`, and `0` otherwise.
That is, 2 to the power `i`.
For the bitwise point of view, it has the `i`th bit as `1` and all other bits as `0`.
-/
def twoPow (w : Nat) (i : Nat) : BitVec w := 1#w <<< i
end bitwise
section normalization_eqs
/-! We add simp-lemmas that rewrite bitvector operations into the equivalent notation -/
@[simp] theorem append_eq (x : BitVec w) (y : BitVec v) : BitVec.append x y = x ++ y := rfl
@[simp] theorem shiftLeft_eq (x : BitVec w) (n : Nat) : BitVec.shiftLeft x n = x <<< n := rfl
@[simp] theorem ushiftRight_eq (x : BitVec w) (n : Nat) : BitVec.ushiftRight x n = x >>> n := rfl
@[simp] theorem not_eq (x : BitVec w) : BitVec.not x = ~~~x := rfl
@[simp] theorem and_eq (x y : BitVec w) : BitVec.and x y = x &&& y := rfl
@[simp] theorem or_eq (x y : BitVec w) : BitVec.or x y = x ||| y := rfl
@[simp] theorem xor_eq (x y : BitVec w) : BitVec.xor x y = x ^^^ y := rfl
@[simp] theorem neg_eq (x : BitVec w) : BitVec.neg x = -x := rfl
@[simp] theorem add_eq (x y : BitVec w) : BitVec.add x y = x + y := rfl
@[simp] theorem sub_eq (x y : BitVec w) : BitVec.sub x y = x - y := rfl
@[simp] theorem mul_eq (x y : BitVec w) : BitVec.mul x y = x * y := rfl
@[simp] theorem zero_eq : BitVec.zero n = 0#n := rfl
end normalization_eqs
/-- Converts a list of `Bool`s to a big-endian `BitVec`. -/
def ofBoolListBE : (bs : List Bool) BitVec bs.length
| [] => 0#0
| b :: bs => cons b (ofBoolListBE bs)
/-- Converts a list of `Bool`s to a little-endian `BitVec`. -/
def ofBoolListLE : (bs : List Bool) BitVec bs.length
| [] => 0#0
| b :: bs => concat (ofBoolListLE bs) b
end BitVec

View File

@@ -0,0 +1,238 @@
/-
Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Harun Khan, Abdalrhman M Mohamed, Joe Hendrix
-/
prelude
import Init.Data.BitVec.Folds
import Init.Data.Nat.Mod
/-!
# Bitblasting of bitvectors
This module provides theorems for showing the equivalence between BitVec operations using
the `Fin 2^n` representation and Boolean vectors. It is still under development, but
intended to provide a path for converting SAT and SMT solver proofs about BitVectors
as vectors of bits into proofs about Lean `BitVec` values.
The module is named for the bit-blasting operation in an SMT solver that converts bitvector
expressions into expressions about individual bits in each vector.
## Main results
* `x + y : BitVec w` is `(adc x y false).2`.
## Future work
All other operations are to be PR'ed later and are already proved in
https://github.com/mhk119/lean-smt/blob/bitvec/Smt/Data/Bitwise.lean.
-/
open Nat Bool
namespace Bool
/-- At least two out of three booleans are true. -/
abbrev atLeastTwo (a b c : Bool) : Bool := a && b || a && c || b && c
@[simp] theorem atLeastTwo_false_left : atLeastTwo false b c = (b && c) := by simp [atLeastTwo]
@[simp] theorem atLeastTwo_false_mid : atLeastTwo a false c = (a && c) := by simp [atLeastTwo]
@[simp] theorem atLeastTwo_false_right : atLeastTwo a b false = (a && b) := by simp [atLeastTwo]
@[simp] theorem atLeastTwo_true_left : atLeastTwo true b c = (b || c) := by cases b <;> cases c <;> simp [atLeastTwo]
@[simp] theorem atLeastTwo_true_mid : atLeastTwo a true c = (a || c) := by cases a <;> cases c <;> simp [atLeastTwo]
@[simp] theorem atLeastTwo_true_right : atLeastTwo a b true = (a || b) := by cases a <;> cases b <;> simp [atLeastTwo]
end Bool
/-! ### Preliminaries -/
namespace BitVec
private theorem testBit_limit {x i : Nat} (x_lt_succ : x < 2^(i+1)) :
testBit x i = decide (x 2^i) := by
cases xi : testBit x i with
| true =>
simp [testBit_implies_ge xi]
| false =>
simp
cases Nat.lt_or_ge x (2^i) with
| inl x_lt =>
exact x_lt
| inr x_ge =>
have j, j_ge, jp := ge_two_pow_implies_high_bit_true x_ge
cases Nat.lt_or_eq_of_le j_ge with
| inr x_eq =>
simp [x_eq, jp] at xi
| inl x_lt =>
exfalso
apply Nat.lt_irrefl
calc x < 2^(i+1) := x_lt_succ
_ 2 ^ j := Nat.pow_le_pow_of_le_right Nat.zero_lt_two x_lt
_ x := testBit_implies_ge jp
private theorem mod_two_pow_succ (x i : Nat) :
x % 2^(i+1) = 2^i*(x.testBit i).toNat + x % (2 ^ i):= by
rw [Nat.mod_pow_succ, Nat.add_comm, Nat.toNat_testBit]
private theorem mod_two_pow_add_mod_two_pow_add_bool_lt_two_pow_succ
(x y i : Nat) (c : Bool) : x % 2^i + (y % 2^i + c.toNat) < 2^(i+1) := by
have : c.toNat 1 := Bool.toNat_le c
rw [Nat.pow_succ]
omega
/-! ### Addition -/
/-- carry i x y c returns true if the `i` carry bit is true when computing `x + y + c`. -/
def carry (i : Nat) (x y : BitVec w) (c : Bool) : Bool :=
decide (x.toNat % 2^i + y.toNat % 2^i + c.toNat 2^i)
@[simp] theorem carry_zero : carry 0 x y c = c := by
cases c <;> simp [carry, mod_one]
theorem carry_succ (i : Nat) (x y : BitVec w) (c : Bool) :
carry (i+1) x y c = atLeastTwo (x.getLsb i) (y.getLsb i) (carry i x y c) := by
simp only [carry, mod_two_pow_succ, atLeastTwo, getLsb]
simp only [Nat.pow_succ']
have sum_bnd : x.toNat%2^i + (y.toNat%2^i + c.toNat) < 2*2^i := by
simp only [ Nat.pow_succ']
exact mod_two_pow_add_mod_two_pow_add_bool_lt_two_pow_succ ..
cases x.toNat.testBit i <;> cases y.toNat.testBit i <;> (simp; omega)
/-- Carry function for bitwise addition. -/
def adcb (x y c : Bool) : Bool × Bool := (atLeastTwo x y c, Bool.xor x (Bool.xor y c))
/-- Bitwise addition implemented via a ripple carry adder. -/
def adc (x y : BitVec w) : Bool Bool × BitVec w :=
iunfoldr fun (i : Fin w) c => adcb (x.getLsb i) (y.getLsb i) c
theorem getLsb_add_add_bool {i : Nat} (i_lt : i < w) (x y : BitVec w) (c : Bool) :
getLsb (x + y + zeroExtend w (ofBool c)) i =
Bool.xor (getLsb x i) (Bool.xor (getLsb y i) (carry i x y c)) := by
let x, x_lt := x
let y, y_lt := y
simp only [getLsb, toNat_add, toNat_zeroExtend, i_lt, toNat_ofFin, toNat_ofBool,
Nat.mod_add_mod, Nat.add_mod_mod]
apply Eq.trans
rw [ Nat.div_add_mod x (2^i), Nat.div_add_mod y (2^i)]
simp only
[ Nat.testBit_mod_two_pow,
Nat.testBit_mul_two_pow_add_eq,
i_lt,
decide_True,
Bool.true_and,
Nat.add_assoc,
Nat.add_left_comm (_%_) (_ * _) _,
testBit_limit (mod_two_pow_add_mod_two_pow_add_bool_lt_two_pow_succ x y i c)
]
simp [testBit_to_div_mod, carry, Nat.add_assoc]
theorem getLsb_add {i : Nat} (i_lt : i < w) (x y : BitVec w) :
getLsb (x + y) i =
Bool.xor (getLsb x i) (Bool.xor (getLsb y i) (carry i x y false)) := by
simpa using getLsb_add_add_bool i_lt x y false
theorem adc_spec (x y : BitVec w) (c : Bool) :
adc x y c = (carry w x y c, x + y + zeroExtend w (ofBool c)) := by
simp only [adc]
apply iunfoldr_replace
(fun i => carry i x y c)
(x + y + zeroExtend w (ofBool c))
c
case init =>
simp [carry, Nat.mod_one]
cases c <;> rfl
case step =>
simp [adcb, Prod.mk.injEq, carry_succ, getLsb_add_add_bool]
theorem add_eq_adc (w : Nat) (x y : BitVec w) : x + y = (adc x y false).snd := by
simp [adc_spec]
/-! ### add -/
/-- Adding a bitvector to its own complement yields the all ones bitpattern -/
@[simp] theorem add_not_self (x : BitVec w) : x + ~~~x = allOnes w := by
rw [add_eq_adc, adc, iunfoldr_replace (fun _ => false) (allOnes w)]
· rfl
· simp [adcb, atLeastTwo]
/-- Subtracting `x` from the all ones bitvector is equivalent to taking its complement -/
theorem allOnes_sub_eq_not (x : BitVec w) : allOnes w - x = ~~~x := by
rw [ add_not_self x, BitVec.add_comm, add_sub_cancel]
/-! ### Negation -/
theorem bit_not_testBit (x : BitVec w) (i : Fin w) :
getLsb (((iunfoldr (fun (i : Fin w) c => (c, !(x.getLsb i)))) ()).snd) i.val = !(getLsb x i.val) := by
apply iunfoldr_getLsb (fun _ => ()) i (by simp)
theorem bit_not_add_self (x : BitVec w) :
((iunfoldr (fun (i : Fin w) c => (c, !(x.getLsb i)))) ()).snd + x = -1 := by
simp only [add_eq_adc]
apply iunfoldr_replace_snd (fun _ => false) (-1) false rfl
intro i; simp only [ BitVec.not, adcb, testBit_toNat]
rw [iunfoldr_replace_snd (fun _ => ()) (((iunfoldr (fun i c => (c, !(x.getLsb i)))) ()).snd)]
<;> simp [bit_not_testBit, negOne_eq_allOnes, getLsb_allOnes]
theorem bit_not_eq_not (x : BitVec w) :
((iunfoldr (fun i c => (c, !(x.getLsb i)))) ()).snd = ~~~ x := by
simp [allOnes_sub_eq_not, BitVec.eq_sub_iff_add_eq.mpr (bit_not_add_self x), negOne_eq_allOnes]
theorem bit_neg_eq_neg (x : BitVec w) : -x = (adc (((iunfoldr (fun (i : Fin w) c => (c, !(x.getLsb i)))) ()).snd) (BitVec.ofNat w 1) false).snd:= by
simp only [ add_eq_adc]
rw [iunfoldr_replace_snd ((fun _ => ())) (((iunfoldr (fun (i : Fin w) c => (c, !(x.getLsb i)))) ()).snd) _ rfl]
· rw [BitVec.eq_sub_iff_add_eq.mpr (bit_not_add_self x), sub_toAdd, BitVec.add_comm _ (-x)]
simp [ sub_toAdd, BitVec.sub_add_cancel]
· simp [bit_not_testBit x _]
/-! ### Inequalities (le / lt) -/
theorem ult_eq_not_carry (x y : BitVec w) : x.ult y = !carry w x (~~~y) true := by
simp only [BitVec.ult, carry, toNat_mod_cancel, toNat_not, toNat_true, ge_iff_le, decide_not,
Nat.not_le, decide_eq_decide]
rw [Nat.mod_eq_of_lt (by omega)]
omega
theorem ule_eq_not_ult (x y : BitVec w) : x.ule y = !y.ult x := by
simp [BitVec.ule, BitVec.ult, decide_not]
theorem ule_eq_carry (x y : BitVec w) : x.ule y = carry w y (~~~x) true := by
simp [ule_eq_not_ult, ult_eq_not_carry]
/-- If two bitvectors have the same `msb`, then signed and unsigned comparisons coincide -/
theorem slt_eq_ult_of_msb_eq {x y : BitVec w} (h : x.msb = y.msb) :
x.slt y = x.ult y := by
simp only [BitVec.slt, toInt_eq_msb_cond, BitVec.ult, decide_eq_decide, h]
cases y.msb <;> simp
/-- If two bitvectors have different `msb`s, then unsigned comparison is determined by this bit -/
theorem ult_eq_msb_of_msb_neq {x y : BitVec w} (h : x.msb y.msb) :
x.ult y = y.msb := by
simp only [BitVec.ult, msb_eq_decide, ne_eq, decide_eq_decide] at *
omega
/-- If two bitvectors have different `msb`s, then signed and unsigned comparisons are opposites -/
theorem slt_eq_not_ult_of_msb_neq {x y : BitVec w} (h : x.msb y.msb) :
x.slt y = !x.ult y := by
simp only [BitVec.slt, toInt_eq_msb_cond, Bool.eq_not_of_ne h, ult_eq_msb_of_msb_neq h]
cases y.msb <;> (simp; omega)
theorem slt_eq_ult (x y : BitVec w) :
x.slt y = (x.msb != y.msb).xor (x.ult y) := by
by_cases h : x.msb = y.msb
· simp [h, slt_eq_ult_of_msb_eq]
· have h' : x.msb != y.msb := by simp_all
simp [slt_eq_not_ult_of_msb_neq h, h']
theorem slt_eq_not_carry (x y : BitVec w) :
x.slt y = (x.msb == y.msb).xor (carry w x (~~~y) true) := by
simp only [slt_eq_ult, bne, ult_eq_not_carry]
cases x.msb == y.msb <;> simp
theorem sle_eq_not_slt (x y : BitVec w) : x.sle y = !y.slt x := by
simp only [BitVec.sle, BitVec.slt, decide_not, decide_eq_decide]; omega
theorem sle_eq_carry (x y : BitVec w) :
x.sle y = !((x.msb == y.msb).xor (carry w y (~~~x) true)) := by
rw [sle_eq_not_slt, slt_eq_not_carry, beq_comm]
end BitVec

View File

@@ -0,0 +1,113 @@
/-
Copyright (c) 2023 Lean FRO, LLC. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Joe Hendrix, Harun Khan
-/
prelude
import Init.Data.BitVec.Lemmas
import Init.Data.Nat.Lemmas
import Init.Data.Fin.Iterate
namespace BitVec
/--
iunfoldr is an iterative operation that applies a function `f` repeatedly.
It produces a sequence of state values `[s_0, s_1 .. s_w]` and a bitvector
`v` where `f i s_i = (s_{i+1}, b_i)` and `b_i` is bit `i`th least-significant bit
in `v` (e.g., `getLsb v i = b_i`).
Theorems involving `iunfoldr` can be eliminated using `iunfoldr_replace` below.
-/
def iunfoldr (f : Fin w -> α α × Bool) (s : α) : α × BitVec w :=
Fin.hIterate (fun i => α × BitVec i) (s, nil) fun i q =>
(fun p => p.fst, cons p.snd q.snd) (f i q.fst)
theorem iunfoldr.fst_eq
{f : Fin w α α × Bool} (state : Nat α) (s : α)
(init : s = state 0)
(ind : (i : Fin w), (f i (state i.val)).fst = state (i.val+1)) :
(iunfoldr f s).fst = state w := by
unfold iunfoldr
apply Fin.hIterate_elim (fun i (p : α × BitVec i) => p.fst = state i)
case init =>
exact init
case step =>
intro i s, v p
simp_all [ind i]
private theorem iunfoldr.eq_test
{f : Fin w α α × Bool} (state : Nat α) (value : BitVec w) (a : α)
(init : state 0 = a)
(step : (i : Fin w), f i (state i.val) = (state (i.val+1), value.getLsb i.val)) :
iunfoldr f a = (state w, BitVec.truncate w value) := by
apply Fin.hIterate_eq (fun i => ((state i, BitVec.truncate i value) : α × BitVec i))
case init =>
simp only [init, eq_nil]
case step =>
intro i
simp_all [truncate_succ]
theorem iunfoldr_getLsb' {f : Fin w α α × Bool} (state : Nat α)
(ind : (i : Fin w), (f i (state i.val)).fst = state (i.val+1)) :
( i : Fin w, getLsb (iunfoldr f (state 0)).snd i.val = (f i (state i.val)).snd)
(iunfoldr f (state 0)).fst = state w := by
unfold iunfoldr
simp
apply Fin.hIterate_elim
(fun j (p : α × BitVec j) => (hj : j w)
( i : Fin j, getLsb p.snd i.val = (f i.val, Nat.lt_of_lt_of_le i.isLt hj (state i.val)).snd)
p.fst = state j)
case hj => simp
case init =>
intro
apply And.intro
· intro i
have := Fin.size_pos i
contradiction
· rfl
case step =>
intro j s, v ih hj
apply And.intro
case left =>
intro i
simp only [getLsb_cons]
have hj2 : j.val w := by simp
cases (Nat.lt_or_eq_of_le (Nat.lt_succ.mp i.isLt)) with
| inl h3 => simp [if_neg, (Nat.ne_of_lt h3)]
exact (ih hj2).1 i.val, h3
| inr h3 => simp [h3, if_pos]
cases (Nat.eq_zero_or_pos j.val) with
| inl hj3 => congr
rw [ (ih hj2).2]
| inr hj3 => congr
exact (ih hj2).2
case right =>
simp
have hj2 : j.val w := by simp
rw [ ind j, (ih hj2).2]
theorem iunfoldr_getLsb {f : Fin w α α × Bool} (state : Nat α) (i : Fin w)
(ind : (i : Fin w), (f i (state i.val)).fst = state (i.val+1)) :
getLsb (iunfoldr f (state 0)).snd i.val = (f i (state i.val)).snd := by
exact (iunfoldr_getLsb' state ind).1 i
/--
Correctness theorem for `iunfoldr`.
-/
theorem iunfoldr_replace
{f : Fin w α α × Bool} (state : Nat α) (value : BitVec w) (a : α)
(init : state 0 = a)
(step : (i : Fin w), f i (state i.val) = (state (i.val+1), value.getLsb i.val)) :
iunfoldr f a = (state w, value) := by
simp [iunfoldr.eq_test state value a init step]
theorem iunfoldr_replace_snd
{f : Fin w α α × Bool} (state : Nat α) (value : BitVec w) (a : α)
(init : state 0 = a)
(step : (i : Fin w), f i (state i.val) = (state (i.val+1), value.getLsb i.val)) :
(iunfoldr f a).snd = value := by
simp [iunfoldr.eq_test state value a init step]
end BitVec

File diff suppressed because it is too large Load Diff

525
src/Init/Data/Bool.lean Normal file
View File

@@ -0,0 +1,525 @@
/-
Copyright (c) 2023 F. G. Dorais. No rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: F. G. Dorais
-/
prelude
import Init.BinderPredicates
/-- Boolean exclusive or -/
abbrev xor : Bool Bool Bool := bne
namespace Bool
/- Namespaced versions that can be used instead of prefixing `_root_` -/
@[inherit_doc not] protected abbrev not := not
@[inherit_doc or] protected abbrev or := or
@[inherit_doc and] protected abbrev and := and
@[inherit_doc xor] protected abbrev xor := xor
instance (p : Bool Prop) [inst : DecidablePred p] : Decidable ( x, p x) :=
match inst true, inst false with
| isFalse ht, _ => isFalse fun h => absurd (h _) ht
| _, isFalse hf => isFalse fun h => absurd (h _) hf
| isTrue ht, isTrue hf => isTrue fun | true => ht | false => hf
instance (p : Bool Prop) [inst : DecidablePred p] : Decidable ( x, p x) :=
match inst true, inst false with
| isTrue ht, _ => isTrue _, ht
| _, isTrue hf => isTrue _, hf
| isFalse ht, isFalse hf => isFalse fun | true, h => absurd h ht | false, h => absurd h hf
@[simp] theorem default_bool : default = false := rfl
instance : LE Bool := (. .)
instance : LT Bool := (!. && .)
instance (x y : Bool) : Decidable (x y) := inferInstanceAs (Decidable (x y))
instance (x y : Bool) : Decidable (x < y) := inferInstanceAs (Decidable (!x && y))
instance : Max Bool := or
instance : Min Bool := and
theorem false_ne_true : false true := Bool.noConfusion
theorem eq_false_or_eq_true : (b : Bool) b = true b = false := by decide
theorem eq_false_iff : {b : Bool} b = false b true := by decide
theorem ne_false_iff : {b : Bool} b false b = true := by decide
theorem eq_iff_iff {a b : Bool} : a = b (a b) := by cases b <;> simp
@[simp] theorem decide_eq_true {b : Bool} [Decidable (b = true)] : decide (b = true) = b := by cases b <;> simp
@[simp] theorem decide_eq_false {b : Bool} [Decidable (b = false)] : decide (b = false) = !b := by cases b <;> simp
@[simp] theorem decide_true_eq {b : Bool} [Decidable (true = b)] : decide (true = b) = b := by cases b <;> simp
@[simp] theorem decide_false_eq {b : Bool} [Decidable (false = b)] : decide (false = b) = !b := by cases b <;> simp
/-! ### and -/
@[simp] theorem and_self_left : (a b : Bool), (a && (a && b)) = (a && b) := by decide
@[simp] theorem and_self_right : (a b : Bool), ((a && b) && b) = (a && b) := by decide
@[simp] theorem not_and_self : (x : Bool), (!x && x) = false := by decide
@[simp] theorem and_not_self : (x : Bool), (x && !x) = false := by decide
/-
Added for confluence with `not_and_self` `and_not_self` on term
`(b && !b) = true` due to reductions:
1. `(b = true !b = true)` via `Bool.and_eq_true`
2. `false = true` via `Bool.and_not_self`
-/
@[simp] theorem eq_true_and_eq_false_self : (b : Bool), (b = true b = false) False := by decide
@[simp] theorem eq_false_and_eq_true_self : (b : Bool), (b = false b = true) False := by decide
theorem and_comm : (x y : Bool), (x && y) = (y && x) := by decide
instance : Std.Commutative (· && ·) := and_comm
theorem and_left_comm : (x y z : Bool), (x && (y && z)) = (y && (x && z)) := by decide
theorem and_right_comm : (x y z : Bool), ((x && y) && z) = ((x && z) && y) := by decide
/-
Bool version `and_iff_left_iff_imp`.
Needed for confluence of term `(a && b) ↔ a` which reduces to `(a && b) = a` via
`Bool.coe_iff_coe` and `a → b` via `Bool.and_eq_true` and
`and_iff_left_iff_imp`.
-/
@[simp] theorem and_iff_left_iff_imp : (a b : Bool), ((a && b) = a) (a b) := by decide
@[simp] theorem and_iff_right_iff_imp : (a b : Bool), ((a && b) = b) (b a) := by decide
@[simp] theorem iff_self_and : (a b : Bool), (a = (a && b)) (a b) := by decide
@[simp] theorem iff_and_self : (a b : Bool), (b = (a && b)) (b a) := by decide
/-! ### or -/
@[simp] theorem or_self_left : (a b : Bool), (a || (a || b)) = (a || b) := by decide
@[simp] theorem or_self_right : (a b : Bool), ((a || b) || b) = (a || b) := by decide
@[simp] theorem not_or_self : (x : Bool), (!x || x) = true := by decide
@[simp] theorem or_not_self : (x : Bool), (x || !x) = true := by decide
/-
Added for confluence with `not_or_self` `or_not_self` on term
`(b || !b) = true` due to reductions:
1. `(b = true !b = true)` via `Bool.or_eq_true`
2. `true = true` via `Bool.or_not_self`
-/
@[simp] theorem eq_true_or_eq_false_self : (b : Bool), (b = true b = false) True := by decide
@[simp] theorem eq_false_or_eq_true_self : (b : Bool), (b = false b = true) True := by decide
/-
Bool version `or_iff_left_iff_imp`.
Needed for confluence of term `(a || b) ↔ a` which reduces to `(a || b) = a` via
`Bool.coe_iff_coe` and `a → b` via `Bool.or_eq_true` and
`and_iff_left_iff_imp`.
-/
@[simp] theorem or_iff_left_iff_imp : (a b : Bool), ((a || b) = a) (b a) := by decide
@[simp] theorem or_iff_right_iff_imp : (a b : Bool), ((a || b) = b) (a b) := by decide
@[simp] theorem iff_self_or : (a b : Bool), (a = (a || b)) (b a) := by decide
@[simp] theorem iff_or_self : (a b : Bool), (b = (a || b)) (a b) := by decide
theorem or_comm : (x y : Bool), (x || y) = (y || x) := by decide
instance : Std.Commutative (· || ·) := or_comm
theorem or_left_comm : (x y z : Bool), (x || (y || z)) = (y || (x || z)) := by decide
theorem or_right_comm : (x y z : Bool), ((x || y) || z) = ((x || z) || y) := by decide
/-! ### distributivity -/
theorem and_or_distrib_left : (x y z : Bool), (x && (y || z)) = (x && y || x && z) := by decide
theorem and_or_distrib_right : (x y z : Bool), ((x || y) && z) = (x && z || y && z) := by decide
theorem or_and_distrib_left : (x y z : Bool), (x || y && z) = ((x || y) && (x || z)) := by decide
theorem or_and_distrib_right : (x y z : Bool), (x && y || z) = ((x || z) && (y || z)) := by decide
theorem and_xor_distrib_left : (x y z : Bool), (x && xor y z) = xor (x && y) (x && z) := by decide
theorem and_xor_distrib_right : (x y z : Bool), (xor x y && z) = xor (x && z) (y && z) := by decide
/-- De Morgan's law for boolean and -/
@[simp] theorem not_and : (x y : Bool), (!(x && y)) = (!x || !y) := by decide
/-- De Morgan's law for boolean or -/
@[simp] theorem not_or : (x y : Bool), (!(x || y)) = (!x && !y) := by decide
theorem and_eq_true_iff (x y : Bool) : (x && y) = true x = true y = true :=
Iff.of_eq (and_eq_true x y)
theorem and_eq_false_iff : (x y : Bool), (x && y) = false x = false y = false := by decide
/-
New simp rule that replaces `Bool.and_eq_false_eq_eq_false_or_eq_false` in
Mathlib due to confluence:
Consider the term: `¬((b && c) = true)`:
1. Reduces to `((b && c) = false)` via `Bool.not_eq_true`
2. Reduces to `¬(b = true ∧ c = true)` via `Bool.and_eq_true`.
1. Further reduces to `b = false c = false` via `Bool.and_eq_false_eq_eq_false_or_eq_false`.
2. Further reduces to `b = true → c = false` via `not_and` and `Bool.not_eq_true`.
-/
@[simp] theorem and_eq_false_imp : (x y : Bool), (x && y) = false (x = true y = false) := by decide
@[simp] theorem or_eq_true_iff : (x y : Bool), (x || y) = true x = true y = true := by decide
@[simp] theorem or_eq_false_iff : (x y : Bool), (x || y) = false x = false y = false := by decide
/-! ### eq/beq/bne -/
/--
These two rules follow trivially by simp, but are needed to avoid non-termination
in false_eq and true_eq.
-/
@[simp] theorem false_eq_true : (false = true) = False := by simp
@[simp] theorem true_eq_false : (true = false) = False := by simp
-- The two lemmas below normalize terms with a constant to the
-- right-hand side but risk non-termination if `false_eq_true` and
-- `true_eq_false` are disabled.
@[simp low] theorem false_eq (b : Bool) : (false = b) = (b = false) := by
cases b <;> simp
@[simp low] theorem true_eq (b : Bool) : (true = b) = (b = true) := by
cases b <;> simp
@[simp] theorem true_beq : b, (true == b) = b := by decide
@[simp] theorem false_beq : b, (false == b) = !b := by decide
@[simp] theorem beq_true : b, (b == true) = b := by decide
instance : Std.LawfulIdentity (· == ·) true where
left_id := true_beq
right_id := beq_true
@[simp] theorem beq_false : b, (b == false) = !b := by decide
@[simp] theorem true_bne : (b : Bool), (true != b) = !b := by decide
@[simp] theorem false_bne : (b : Bool), (false != b) = b := by decide
@[simp] theorem bne_true : (b : Bool), (b != true) = !b := by decide
@[simp] theorem bne_false : (b : Bool), (b != false) = b := by decide
instance : Std.LawfulIdentity (· != ·) false where
left_id := false_bne
right_id := bne_false
@[simp] theorem not_beq_self : (x : Bool), ((!x) == x) = false := by decide
@[simp] theorem beq_not_self : (x : Bool), (x == !x) = false := by decide
@[simp] theorem not_bne_self : (x : Bool), ((!x) != x) = true := by decide
@[simp] theorem bne_not_self : (x : Bool), (x != !x) = true := by decide
/-
Added for equivalence with `Bool.not_beq_self` and needed for confluence
due to `beq_iff_eq`.
-/
@[simp] theorem not_eq_self : (b : Bool), ((!b) = b) False := by decide
@[simp] theorem eq_not_self : (b : Bool), (b = (!b)) False := by decide
@[simp] theorem beq_self_left : (a b : Bool), (a == (a == b)) = b := by decide
@[simp] theorem beq_self_right : (a b : Bool), ((a == b) == b) = a := by decide
@[simp] theorem bne_self_left : (a b : Bool), (a != (a != b)) = b := by decide
@[simp] theorem bne_self_right : (a b : Bool), ((a != b) != b) = a := by decide
@[simp] theorem not_bne_not : (x y : Bool), ((!x) != (!y)) = (x != y) := by decide
@[simp] theorem bne_assoc : (x y z : Bool), ((x != y) != z) = (x != (y != z)) := by decide
instance : Std.Associative (· != ·) := bne_assoc
@[simp] theorem bne_left_inj : (x y z : Bool), (x != y) = (x != z) y = z := by decide
@[simp] theorem bne_right_inj : (x y z : Bool), (x != z) = (y != z) x = y := by decide
theorem eq_not_of_ne : {x y : Bool}, x y x = !y := by decide
/-! ### coercision related normal forms -/
theorem beq_eq_decide_eq [BEq α] [LawfulBEq α] [DecidableEq α] (a b : α) :
(a == b) = decide (a = b) := by
cases h : a == b
· simp [ne_of_beq_false h]
· simp [eq_of_beq h]
@[simp] theorem not_eq_not : {a b : Bool}, ¬a = !b a = b := by decide
@[simp] theorem not_not_eq : {a b : Bool}, ¬(!a) = b a = b := by decide
@[simp] theorem coe_iff_coe : (a b : Bool), (a b) a = b := by decide
@[simp] theorem coe_true_iff_false : (a b : Bool), (a b = false) a = (!b) := by decide
@[simp] theorem coe_false_iff_true : (a b : Bool), (a = false b) (!a) = b := by decide
@[simp] theorem coe_false_iff_false : (a b : Bool), (a = false b = false) (!a) = (!b) := by decide
/-! ### beq properties -/
theorem beq_comm {α} [BEq α] [LawfulBEq α] {a b : α} : (a == b) = (b == a) :=
(Bool.coe_iff_coe (a == b) (b == a)).mp (by simp [@eq_comm α])
/-! ### xor -/
theorem false_xor : (x : Bool), xor false x = x := false_bne
theorem xor_false : (x : Bool), xor x false = x := bne_false
theorem true_xor : (x : Bool), xor true x = !x := true_bne
theorem xor_true : (x : Bool), xor x true = !x := bne_true
theorem not_xor_self : (x : Bool), xor (!x) x = true := not_bne_self
theorem xor_not_self : (x : Bool), xor x (!x) = true := bne_not_self
theorem not_xor : (x y : Bool), xor (!x) y = !(xor x y) := by decide
theorem xor_not : (x y : Bool), xor x (!y) = !(xor x y) := by decide
theorem not_xor_not : (x y : Bool), xor (!x) (!y) = (xor x y) := not_bne_not
theorem xor_self : (x : Bool), xor x x = false := by decide
theorem xor_comm : (x y : Bool), xor x y = xor y x := by decide
theorem xor_left_comm : (x y z : Bool), xor x (xor y z) = xor y (xor x z) := by decide
theorem xor_right_comm : (x y z : Bool), xor (xor x y) z = xor (xor x z) y := by decide
theorem xor_assoc : (x y z : Bool), xor (xor x y) z = xor x (xor y z) := bne_assoc
theorem xor_left_inj : (x y z : Bool), xor x y = xor x z y = z := bne_left_inj
theorem xor_right_inj : (x y z : Bool), xor x z = xor y z x = y := bne_right_inj
/-! ### le/lt -/
@[simp] protected theorem le_true : (x : Bool), x true := by decide
@[simp] protected theorem false_le : (x : Bool), false x := by decide
@[simp] protected theorem le_refl : (x : Bool), x x := by decide
@[simp] protected theorem lt_irrefl : (x : Bool), ¬ x < x := by decide
protected theorem le_trans : {x y z : Bool}, x y y z x z := by decide
protected theorem le_antisymm : {x y : Bool}, x y y x x = y := by decide
protected theorem le_total : (x y : Bool), x y y x := by decide
protected theorem lt_asymm : {x y : Bool}, x < y ¬ y < x := by decide
protected theorem lt_trans : {x y z : Bool}, x < y y < z x < z := by decide
protected theorem lt_iff_le_not_le : {x y : Bool}, x < y x y ¬ y x := by decide
protected theorem lt_of_le_of_lt : {x y z : Bool}, x y y < z x < z := by decide
protected theorem lt_of_lt_of_le : {x y z : Bool}, x < y y z x < z := by decide
protected theorem le_of_lt : {x y : Bool}, x < y x y := by decide
protected theorem le_of_eq : {x y : Bool}, x = y x y := by decide
protected theorem ne_of_lt : {x y : Bool}, x < y x y := by decide
protected theorem lt_of_le_of_ne : {x y : Bool}, x y x y x < y := by decide
protected theorem le_of_lt_or_eq : {x y : Bool}, x < y x = y x y := by decide
protected theorem eq_true_of_true_le : {x : Bool}, true x x = true := by decide
protected theorem eq_false_of_le_false : {x : Bool}, x false x = false := by decide
/-! ### min/max -/
@[simp] protected theorem max_eq_or : max = or := rfl
@[simp] protected theorem min_eq_and : min = and := rfl
/-! ### injectivity lemmas -/
theorem not_inj : {x y : Bool}, (!x) = (!y) x = y := by decide
theorem not_inj_iff : {x y : Bool}, (!x) = (!y) x = y := by decide
theorem and_or_inj_right : {m x y : Bool}, (x && m) = (y && m) (x || m) = (y || m) x = y := by
decide
theorem and_or_inj_right_iff :
{m x y : Bool}, (x && m) = (y && m) (x || m) = (y || m) x = y := by decide
theorem and_or_inj_left : {m x y : Bool}, (m && x) = (m && y) (m || x) = (m || y) x = y := by
decide
theorem and_or_inj_left_iff :
{m x y : Bool}, (m && x) = (m && y) (m || x) = (m || y) x = y := by decide
/-! ## toNat -/
/-- convert a `Bool` to a `Nat`, `false -> 0`, `true -> 1` -/
def toNat (b:Bool) : Nat := cond b 1 0
@[simp] theorem toNat_false : false.toNat = 0 := rfl
@[simp] theorem toNat_true : true.toNat = 1 := rfl
theorem toNat_le (c : Bool) : c.toNat 1 := by
cases c <;> trivial
@[deprecated toNat_le (since := "2024-02-23")]
abbrev toNat_le_one := toNat_le
theorem toNat_lt (b : Bool) : b.toNat < 2 :=
Nat.lt_succ_of_le (toNat_le _)
@[simp] theorem toNat_eq_zero (b : Bool) : b.toNat = 0 b = false := by
cases b <;> simp
@[simp] theorem toNat_eq_one (b : Bool) : b.toNat = 1 b = true := by
cases b <;> simp
/-! ### ite -/
@[simp] theorem if_true_left (p : Prop) [h : Decidable p] (f : Bool) :
(ite p true f) = (p || f) := by cases h with | _ p => simp [p]
@[simp] theorem if_false_left (p : Prop) [h : Decidable p] (f : Bool) :
(ite p false f) = (!p && f) := by cases h with | _ p => simp [p]
@[simp] theorem if_true_right (p : Prop) [h : Decidable p] (t : Bool) :
(ite p t true) = (!(p : Bool) || t) := by cases h with | _ p => simp [p]
@[simp] theorem if_false_right (p : Prop) [h : Decidable p] (t : Bool) :
(ite p t false) = (p && t) := by cases h with | _ p => simp [p]
@[simp] theorem ite_eq_true_distrib (p : Prop) [h : Decidable p] (t f : Bool) :
(ite p t f = true) = ite p (t = true) (f = true) := by
cases h with | _ p => simp [p]
@[simp] theorem ite_eq_false_distrib (p : Prop) [h : Decidable p] (t f : Bool) :
(ite p t f = false) = ite p (t = false) (f = false) := by
cases h with | _ p => simp [p]
/-
`not_ite_eq_true_eq_true` and related theorems below are added for
non-confluence. A motivating example is
`¬((if u then b else c) = true)`.
This reduces to:
1. `¬((if u then (b = true) else (c = true))` via `ite_eq_true_distrib`
2. `(if u then b c) = false)` via `Bool.not_eq_true`.
Similar logic holds for `¬((if u then b else c) = false)` and related
lemmas.
-/
@[simp]
theorem not_ite_eq_true_eq_true (p : Prop) [h : Decidable p] (b c : Bool) :
¬(ite p (b = true) (c = true)) (ite p (b = false) (c = false)) := by
cases h with | _ p => simp [p]
@[simp]
theorem not_ite_eq_false_eq_false (p : Prop) [h : Decidable p] (b c : Bool) :
¬(ite p (b = false) (c = false)) (ite p (b = true) (c = true)) := by
cases h with | _ p => simp [p]
@[simp]
theorem not_ite_eq_true_eq_false (p : Prop) [h : Decidable p] (b c : Bool) :
¬(ite p (b = true) (c = false)) (ite p (b = false) (c = true)) := by
cases h with | _ p => simp [p]
@[simp]
theorem not_ite_eq_false_eq_true (p : Prop) [h : Decidable p] (b c : Bool) :
¬(ite p (b = false) (c = true)) (ite p (b = true) (c = false)) := by
cases h with | _ p => simp [p]
/-
Added for confluence between `if_true_left` and `ite_false_same` on
`if b = true then True else b = true`
-/
@[simp] theorem eq_false_imp_eq_true : (b:Bool), (b = false b = true) (b = true) := by decide
/-
Added for confluence between `if_true_left` and `ite_false_same` on
`if b = false then True else b = false`
-/
@[simp] theorem eq_true_imp_eq_false : (b:Bool), (b = true b = false) (b = false) := by decide
/-! ### cond -/
theorem cond_eq_ite {α} (b : Bool) (t e : α) : cond b t e = if b then t else e := by
cases b <;> simp
theorem cond_eq_if : (bif b then x else y) = (if b then x else y) := cond_eq_ite b x y
@[simp] theorem cond_not (b : Bool) (t e : α) : cond (!b) t e = cond b e t := by
cases b <;> rfl
@[simp] theorem cond_self (c : Bool) (t : α) : cond c t t = t := by cases c <;> rfl
/-
This is a simp rule in Mathlib, but results in non-confluence that is difficult
to fix as decide distributes over propositions. As an example, observe that
`cond (decide (p ∧ q)) t f` could simplify to either:
* `if p ∧ q then t else f` via `Bool.cond_decide` or
* `cond (decide p && decide q) t f` via `Bool.decide_and`.
A possible approach to improve normalization between `cond` and `ite` would be
to completely simplify away `cond` by making `cond_eq_ite` a `simp` rule, but
that has not been taken since it could surprise users to migrate pure `Bool`
operations like `cond` to a mix of `Prop` and `Bool`.
-/
theorem cond_decide {α} (p : Prop) [Decidable p] (t e : α) :
cond (decide p) t e = if p then t else e := by
simp [cond_eq_ite]
@[simp] theorem cond_eq_ite_iff (a : Bool) (p : Prop) [h : Decidable p] (x y u v : α) :
(cond a x y = ite p u v) ite a x y = ite p u v := by
simp [Bool.cond_eq_ite]
@[simp] theorem ite_eq_cond_iff (p : Prop) [h : Decidable p] (a : Bool) (x y u v : α) :
(ite p x y = cond a u v) ite p x y = ite a u v := by
simp [Bool.cond_eq_ite]
@[simp] theorem cond_eq_true_distrib : (c t f : Bool),
(cond c t f = true) = ite (c = true) (t = true) (f = true) := by
decide
@[simp] theorem cond_eq_false_distrib : (c t f : Bool),
(cond c t f = false) = ite (c = true) (t = false) (f = false) := by decide
protected theorem cond_true {α : Type u} {a b : α} : cond true a b = a := cond_true a b
protected theorem cond_false {α : Type u} {a b : α} : cond false a b = b := cond_false a b
@[simp] theorem cond_true_left : (c f : Bool), cond c true f = ( c || f) := by decide
@[simp] theorem cond_false_left : (c f : Bool), cond c false f = (!c && f) := by decide
@[simp] theorem cond_true_right : (c t : Bool), cond c t true = (!c || t) := by decide
@[simp] theorem cond_false_right : (c t : Bool), cond c t false = ( c && t) := by decide
@[simp] theorem cond_true_same : (c b : Bool), cond c c b = (c || b) := by decide
@[simp] theorem cond_false_same : (c b : Bool), cond c b c = (c && b) := by decide
/-# decidability -/
protected theorem decide_coe (b : Bool) [Decidable (b = true)] : decide (b = true) = b := decide_eq_true
@[simp] theorem decide_and (p q : Prop) [dpq : Decidable (p q)] [dp : Decidable p] [dq : Decidable q] :
decide (p q) = (p && q) := by
cases dp with | _ p => simp [p]
@[simp] theorem decide_or (p q : Prop) [dpq : Decidable (p q)] [dp : Decidable p] [dq : Decidable q] :
decide (p q) = (p || q) := by
cases dp with | _ p => simp [p]
@[simp] theorem decide_iff_dist (p q : Prop) [dpq : Decidable (p q)] [dp : Decidable p] [dq : Decidable q] :
decide (p q) = (decide p == decide q) := by
cases dp with | _ p => simp [p]
end Bool
export Bool (cond_eq_if)
/-! ### decide -/
@[simp] theorem false_eq_decide_iff {p : Prop} [h : Decidable p] : false = decide p ¬p := by
cases h with | _ q => simp [q]
@[simp] theorem true_eq_decide_iff {p : Prop} [h : Decidable p] : true = decide p p := by
cases h with | _ q => simp [q]

View File

@@ -52,9 +52,13 @@ def get : (a : @& ByteArray) → (@& Fin a.size) → UInt8
instance : GetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
getElem xs i h := xs.get i, h
instance : LawfulGetElem ByteArray Nat UInt8 fun xs i => i < xs.size where
instance : GetElem ByteArray USize UInt8 fun xs i => i.val < xs.size where
getElem xs i h := xs.uget i h
instance : LawfulGetElem ByteArray USize UInt8 fun xs i => i.val < xs.size where
@[extern "lean_byte_array_set"]
def set! : ByteArray (@& Nat) UInt8 ByteArray
| bs, i, b => bs.set! i b
@@ -195,18 +199,6 @@ instance : ToString ByteArray := ⟨fun bs => bs.toList.toString⟩
/-- Interpret a `ByteArray` of size 8 as a little-endian `UInt64`. -/
def ByteArray.toUInt64LE! (bs : ByteArray) : UInt64 :=
assert! bs.size == 8
(bs.get! 0).toUInt64 <<< 0x38 |||
(bs.get! 1).toUInt64 <<< 0x30 |||
(bs.get! 2).toUInt64 <<< 0x28 |||
(bs.get! 3).toUInt64 <<< 0x20 |||
(bs.get! 4).toUInt64 <<< 0x18 |||
(bs.get! 5).toUInt64 <<< 0x10 |||
(bs.get! 6).toUInt64 <<< 0x8 |||
(bs.get! 7).toUInt64
/-- Interpret a `ByteArray` of size 8 as a big-endian `UInt64`. -/
def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
assert! bs.size == 8
(bs.get! 7).toUInt64 <<< 0x38 |||
(bs.get! 6).toUInt64 <<< 0x30 |||
@@ -216,3 +208,15 @@ def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
(bs.get! 2).toUInt64 <<< 0x10 |||
(bs.get! 1).toUInt64 <<< 0x8 |||
(bs.get! 0).toUInt64
/-- Interpret a `ByteArray` of size 8 as a big-endian `UInt64`. -/
def ByteArray.toUInt64BE! (bs : ByteArray) : UInt64 :=
assert! bs.size == 8
(bs.get! 0).toUInt64 <<< 0x38 |||
(bs.get! 1).toUInt64 <<< 0x30 |||
(bs.get! 2).toUInt64 <<< 0x28 |||
(bs.get! 3).toUInt64 <<< 0x20 |||
(bs.get! 4).toUInt64 <<< 0x18 |||
(bs.get! 5).toUInt64 <<< 0x10 |||
(bs.get! 6).toUInt64 <<< 0x8 |||
(bs.get! 7).toUInt64

72
src/Init/Data/Cast.lean Normal file
View File

@@ -0,0 +1,72 @@
/-
Copyright (c) 2014 Mario Carneiro. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Mario Carneiro, Gabriel Ebner
-/
prelude
import Init.Coe
/-!
# `NatCast`
We introduce the typeclass `NatCast R` for a type `R` with a "canonical
homomorphism" `Nat → R`. The typeclass carries the data of the function,
but no required axioms.
This typeclass was introduced to support a uniform `simp` normal form
for such morphisms.
Without such a typeclass, we would have specific coercions such as
`Int.ofNat`, but also later the generic coercion from `Nat` into any
Mathlib semiring (including `Int`), and we would need to use `simp` to
move between them. However `simp` lemmas expressed using a non-normal
form on the LHS would then not fire.
Typically different instances of this class for the same target type `R`
are definitionally equal, and so differences in the instance do not
block `simp` or `rw`.
This logic also applies to `Int` and so we also introduce `IntCast` alongside
`Int.
## Note about coercions into arbitrary types:
Coercions such as `Nat.cast` that go from a concrete structure such as
`Nat` to an arbitrary type `R` should be set up as follows:
```lean
instance : CoeTail Nat R where coe := ...
instance : CoeHTCT Nat R where coe := ...
```
It needs to be `CoeTail` instead of `Coe` because otherwise type-class
inference would loop when constructing the transitive coercion `Nat →
Nat → Nat → ...`. Sometimes we also need to declare the `CoeHTCT`
instance if we need to shadow another coercion.
-/
/-- Type class for the canonical homomorphism `Nat → R`. -/
class NatCast (R : Type u) where
/-- The canonical map `Nat → R`. -/
protected natCast : Nat R
instance : NatCast Nat where natCast n := n
/--
Canonical homomorphism from `Nat` to a type `R`.
It contains just the function, with no axioms.
In practice, the target type will likely have a (semi)ring structure,
and this homomorphism should be a ring homomorphism.
The prototypical example is `Int.ofNat`.
This class and `IntCast` exist to allow different libraries with their own types that can be notated as natural numbers to have consistent `simp` normal forms without needing to create coercion simplification sets that are aware of all combinations. Libraries should make it easy to work with `NatCast` where possible. For instance, in Mathlib there will be such a homomorphism (and thus a `NatCast R` instance) whenever `R` is an additive monoid with a `1`.
-/
@[coe, reducible, match_pattern] protected def Nat.cast {R : Type u} [NatCast R] : Nat R :=
NatCast.natCast
-- see the notes about coercions into arbitrary types in the module doc-string
instance [NatCast R] : CoeTail Nat R where coe := Nat.cast
-- see the notes about coercions into arbitrary types in the module doc-string
instance [NatCast R] : CoeHTCT Nat R where coe := Nat.cast

View File

@@ -41,7 +41,7 @@ Sends a message on an `Channel`.
This function does not block.
-/
def Channel.send (v : α) (ch : Channel α) : BaseIO Unit :=
def Channel.send (ch : Channel α) (v : α) : BaseIO Unit :=
ch.atomically do
let st get
if st.closed then return

View File

@@ -5,3 +5,4 @@ Authors: Leonardo de Moura
-/
prelude
import Init.Data.Char.Basic
import Init.Data.Char.Lemmas

View File

@@ -40,7 +40,7 @@ theorem isValidUInt32 (n : Nat) (h : isValidCharNat n) : n < UInt32.size := by
apply Nat.lt_trans h₂
decide
theorem isValidChar_of_isValidChar_Nat (n : Nat) (h : isValidCharNat n) : isValidChar (UInt32.ofNat' n (isValidUInt32 n h)) :=
theorem isValidChar_of_isValidCharNat (n : Nat) (h : isValidCharNat n) : isValidChar (UInt32.ofNat' n (isValidUInt32 n h)) :=
match h with
| Or.inl h => Or.inl h
| Or.inr h₁, h₂ => Or.inr h₁, h₂
@@ -52,6 +52,13 @@ theorem isValidChar_zero : isValidChar 0 :=
@[inline] def toNat (c : Char) : Nat :=
c.val.toNat
/-- Convert a character into a `UInt8`, by truncating (reducing modulo 256) if necessary. -/
@[inline] def toUInt8 (c : Char) : UInt8 :=
c.val.toUInt8
/-- The numbers from 0 to 256 are all valid UTF-8 characters, so we can embed one in the other. -/
def ofUInt8 (n : UInt8) : Char := n.toUInt32, .inl (Nat.lt_trans n.1.2 (by decide))
instance : Inhabited Char where
default := 'A'

View File

@@ -0,0 +1,41 @@
/-
Copyright (c) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import Init.Data.Char.Basic
import Init.Data.UInt.Lemmas
namespace Char
theorem le_def {a b : Char} : a b a.1 b.1 := .rfl
theorem lt_def {a b : Char} : a < b a.1 < b.1 := .rfl
theorem lt_iff_val_lt_val {a b : Char} : a < b a.val < b.val := Iff.rfl
@[simp] protected theorem not_le {a b : Char} : ¬ a b b < a := UInt32.not_le
@[simp] protected theorem not_lt {a b : Char} : ¬ a < b b a := UInt32.not_lt
@[simp] protected theorem le_refl (a : Char) : a a := by simp [le_def]
@[simp] protected theorem lt_irrefl (a : Char) : ¬ a < a := by simp
protected theorem le_trans {a b c : Char} : a b b c a c := UInt32.le_trans
protected theorem lt_trans {a b c : Char} : a < b b < c a < c := UInt32.lt_trans
protected theorem le_total (a b : Char) : a b b a := UInt32.le_total a.1 b.1
protected theorem lt_asymm {a b : Char} (h : a < b) : ¬ b < a := UInt32.lt_asymm h
protected theorem ne_of_lt {a b : Char} (h : a < b) : a b := Char.ne_of_val_ne (UInt32.ne_of_lt h)
theorem utf8Size_eq (c : Char) : c.utf8Size = 1 c.utf8Size = 2 c.utf8Size = 3 c.utf8Size = 4 := by
have := c.utf8Size_pos
have := c.utf8Size_le_four
omega
@[simp] theorem ofNat_toNat (c : Char) : Char.ofNat c.toNat = c := by
rw [Char.ofNat, dif_pos]
rfl
@[ext] theorem Char.ext : {a b : Char} a.val = b.val a = b
| _,_, _,_, rfl => rfl
theorem Char.ext_iff {x y : Char} : x = y x.val = y.val := congrArg _, Char.ext
end Char
@[deprecated Char.utf8Size (since := "2024-06-04")] abbrev String.csize := Char.utf8Size

View File

@@ -6,3 +6,6 @@ Author: Leonardo de Moura
prelude
import Init.Data.Fin.Basic
import Init.Data.Fin.Log2
import Init.Data.Fin.Iterate
import Init.Data.Fin.Fold
import Init.Data.Fin.Lemmas

View File

@@ -1,12 +1,10 @@
/-
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
Author: Leonardo de Moura, Robert Y. Lewis, Keeley Hoek, Mario Carneiro
-/
prelude
import Init.Data.Nat.Div
import Init.Data.Nat.Bitwise
import Init.Coe
import Init.Data.Nat.Bitwise.Basic
open Nat
@@ -15,17 +13,40 @@ namespace Fin
instance coeToNat : CoeOut (Fin n) Nat :=
fun v => v.val
/--
From the empty type `Fin 0`, any desired result `α` can be derived. This is simlar to `Empty.elim`.
-/
def elim0.{u} {α : Sort u} : Fin 0 α
| _, h => absurd h (not_lt_zero _)
/--
Returns the successor of the argument.
The bound in the result type is increased:
```
(2 : Fin 3).succ = (3 : Fin 4)
```
This differs from addition, which wraps around:
```
(2 : Fin 3) + 1 = (0 : Fin 3)
```
-/
def succ : Fin n Fin n.succ
| i, h => i+1, Nat.succ_lt_succ h
variable {n : Nat}
/--
Returns `a` modulo `n + 1` as a `Fin n.succ`.
-/
protected def ofNat {n : Nat} (a : Nat) : Fin n.succ :=
a % (n+1), Nat.mod_lt _ (Nat.zero_lt_succ _)
/--
Returns `a` modulo `n` as a `Fin n`.
The assumption `n > 0` ensures that `Fin n` is nonempty.
-/
protected def ofNat' {n : Nat} (a : Nat) (h : n > 0) : Fin n :=
a % n, Nat.mod_lt _ h
@@ -35,14 +56,34 @@ private theorem mlt {b : Nat} : {a : Nat} → a < n → b % n < n
have : n > 0 := Nat.lt_trans (Nat.zero_lt_succ _) h;
Nat.mod_lt _ this
/-- Addition modulo `n` -/
protected def add : Fin n Fin n Fin n
| a, h, b, _ => (a + b) % n, mlt h
/-- Multiplication modulo `n` -/
protected def mul : Fin n Fin n Fin n
| a, h, b, _ => (a * b) % n, mlt h
/-- Subtraction modulo `n` -/
protected def sub : Fin n Fin n Fin n
| a, h, b, _ => (a + (n - b)) % n, mlt h
/-
The definition of `Fin.sub` has been updated to improve performance.
The right-hand-side of the following `match` was originally
```
⟨(a + (n - b)) % n, mlt h⟩
```
This caused significant performance issues when testing definitional equality,
such as `x =?= x - 1` where `x : Fin n` and `n` is a big number,
as Lean spent a long time reducing
```
((n - 1) + x.val) % n
```
For example, this was an issue for `Fin 2^64` (i.e., `UInt64`).
This change improves performance by leveraging the fact that `Nat.add` is defined
using recursion on the second argument.
See issue #4413.
-/
| a, h, b, _ => ((n - b) + a) % n, mlt h
/-!
Remark: land/lor can be defined without using (% n), but
@@ -106,6 +147,8 @@ instance instOfNat : OfNat (Fin (no_index (n+1))) i where
instance : Inhabited (Fin (no_index (n+1))) where
default := 0
@[simp] theorem zero_eta : (0, Nat.zero_lt_succ _ : Fin (n + 1)) = 0 := rfl
theorem val_ne_of_ne {i j : Fin n} (h : i j) : val i val j :=
fun h' => absurd (eq_of_val_eq h') h
@@ -115,10 +158,59 @@ theorem modn_lt : ∀ {m : Nat} (i : Fin n), m > 0 → (modn i m).val < m
theorem val_lt_of_le (i : Fin b) (h : b n) : i.val < n :=
Nat.lt_of_lt_of_le i.isLt h
protected theorem pos (i : Fin n) : 0 < n :=
Nat.lt_of_le_of_lt (Nat.zero_le _) i.2
/-- The greatest value of `Fin (n+1)`. -/
@[inline] def last (n : Nat) : Fin (n + 1) := n, n.lt_succ_self
/-- `castLT i h` embeds `i` into a `Fin` where `h` proves it belongs into. -/
@[inline] def castLT (i : Fin m) (h : i.1 < n) : Fin n := i.1, h
/-- `castLE h i` embeds `i` into a larger `Fin` type. -/
@[inline] def castLE (h : n m) (i : Fin n) : Fin m := i, Nat.lt_of_lt_of_le i.2 h
/-- `cast eq i` embeds `i` into an equal `Fin` type. -/
@[inline] def cast (eq : n = m) (i : Fin n) : Fin m := i, eq i.2
/-- `castAdd m i` embeds `i : Fin n` in `Fin (n+m)`. See also `Fin.natAdd` and `Fin.addNat`. -/
@[inline] def castAdd (m) : Fin n Fin (n + m) :=
castLE <| Nat.le_add_right n m
/-- `castSucc i` embeds `i : Fin n` in `Fin (n+1)`. -/
@[inline] def castSucc : Fin n Fin (n + 1) := castAdd 1
/-- `addNat m i` adds `m` to `i`, generalizes `Fin.succ`. -/
def addNat (i : Fin n) (m) : Fin (n + m) := i + m, Nat.add_lt_add_right i.2 _
/-- `natAdd n i` adds `n` to `i` "on the left". -/
def natAdd (n) (i : Fin m) : Fin (n + m) := n + i, Nat.add_lt_add_left i.2 _
/-- Maps `0` to `n-1`, `1` to `n-2`, ..., `n-1` to `0`. -/
@[inline] def rev (i : Fin n) : Fin n := n - (i + 1), Nat.sub_lt i.pos (Nat.succ_pos _)
/-- `subNat i h` subtracts `m` from `i`, generalizes `Fin.pred`. -/
@[inline] def subNat (m) (i : Fin (n + m)) (h : m i) : Fin n :=
i - m, Nat.sub_lt_right_of_lt_add h i.2
/-- Predecessor of a nonzero element of `Fin (n+1)`. -/
@[inline] def pred {n : Nat} (i : Fin (n + 1)) (h : i 0) : Fin n :=
subNat 1 i <| Nat.pos_of_ne_zero <| mt (Fin.eq_of_val_eq (j := 0)) h
theorem val_inj {a b : Fin n} : a.1 = b.1 a = b := Fin.eq_of_val_eq, Fin.val_eq_of_eq
theorem val_congr {n : Nat} {a b : Fin n} (h : a = b) : (a : Nat) = (b : Nat) :=
Fin.val_inj.mpr h
theorem val_le_of_le {n : Nat} {a b : Fin n} (h : a b) : (a : Nat) (b : Nat) := h
theorem val_le_of_ge {n : Nat} {a b : Fin n} (h : a b) : (b : Nat) (a : Nat) := h
theorem val_add_one_le_of_lt {n : Nat} {a b : Fin n} (h : a < b) : (a : Nat) + 1 (b : Nat) := h
theorem val_add_one_le_of_gt {n : Nat} {a b : Fin n} (h : a > b) : (b : Nat) + 1 (a : Nat) := h
theorem exists_iff {p : Fin n Prop} : (Exists fun i => p i) Exists fun i => Exists fun h => p i, h :=
fun i, hi, hpi => i, hi, hpi, fun i, hi, hpi => i, hi, hpi
end Fin
instance [GetElem cont Nat elem dom] : GetElem cont (Fin n) elem fun xs i => dom xs i where
getElem xs i h := getElem xs i.1 h
macro_rules
| `(tactic| get_elem_tactic_trivial) => `(tactic| apply Fin.val_lt_of_le; get_elem_tactic_trivial; done)

Some files were not shown because too many files have changed in this diff Show More