mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-30 16:54:08 +00:00
Compare commits
39 Commits
decide_tru
...
findSomeM
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5df70e4446 | ||
|
|
6bebfc430e | ||
|
|
b1dee4a42e | ||
|
|
a54226196d | ||
|
|
196b1e9250 | ||
|
|
345ecd20c9 | ||
|
|
7f0fe20315 | ||
|
|
1e98fd7f2d | ||
|
|
76d32cbd2a | ||
|
|
15139b6ef6 | ||
|
|
14c3d4b1a6 | ||
|
|
910b20fb2c | ||
|
|
4df71ed24f | ||
|
|
406da78fc6 | ||
|
|
5d2bd1e2e4 | ||
|
|
c31daece6c | ||
|
|
c157ddda11 | ||
|
|
c77b6a2c64 | ||
|
|
c6e4947f4a | ||
|
|
01814185a6 | ||
|
|
47d0060934 | ||
|
|
b1c2d851e5 | ||
|
|
970dc6f7aa | ||
|
|
8e2f92607f | ||
|
|
ee1fa6eeb7 | ||
|
|
9d2a017704 | ||
|
|
574b86c247 | ||
|
|
75602f7c29 | ||
|
|
0fd90c1283 | ||
|
|
128b049904 | ||
|
|
0e3f26e6df | ||
|
|
1148e6e142 | ||
|
|
02baaa42ff | ||
|
|
e573676db1 | ||
|
|
4dab6a108c | ||
|
|
a4d521cf96 | ||
|
|
99070bf304 | ||
|
|
93dd6f2b36 | ||
|
|
c61ced3f15 |
8
.github/dependabot.yml
vendored
Normal file
8
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
commit-message:
|
||||
prefix: "chore: CI"
|
||||
2
.github/workflows/actionlint.yml
vendored
2
.github/workflows/actionlint.yml
vendored
@@ -17,6 +17,6 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: actionlint
|
||||
uses: raven-actions/actionlint@v1
|
||||
uses: raven-actions/actionlint@v2
|
||||
with:
|
||||
pyflakes: false # we do not use python scripts
|
||||
|
||||
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -318,7 +318,7 @@ jobs:
|
||||
if: github.event_name == 'pull_request'
|
||||
# (needs to be after "Checkout" so files don't get overridden)
|
||||
- name: Setup emsdk
|
||||
uses: mymindstorm/setup-emsdk@v12
|
||||
uses: mymindstorm/setup-emsdk@v14
|
||||
with:
|
||||
version: 3.1.44
|
||||
actions-cache-folder: emsdk
|
||||
@@ -415,7 +415,11 @@ jobs:
|
||||
- name: Test
|
||||
id: test
|
||||
run: |
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/stage1 -j$NPROC --output-junit test-results.xml ${{ matrix.CTEST_OPTIONS }}
|
||||
# give Linux debug unlimited stack, we're not interested in its specific stack usage
|
||||
if [[ '${{ matrix.name }}' == 'Linux Debug' ]]; then
|
||||
ulimit -s unlimited
|
||||
fi
|
||||
time ctest --preset ${{ matrix.CMAKE_PRESET || 'release' }} --test-dir build/stage1 -j$NPROC --output-junit test-results.xml ${{ matrix.CTEST_OPTIONS }} -E "leanruntest_task_test_io"
|
||||
if: (matrix.wasm || !matrix.cross) && needs.configure.outputs.check-level >= 1
|
||||
- name: Test Summary
|
||||
uses: test-summary/action@v2
|
||||
@@ -492,7 +496,7 @@ jobs:
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
@@ -536,7 +540,7 @@ jobs:
|
||||
echo -e "\n*Full commit log*\n" >> diff.md
|
||||
git log --oneline "$last_tag"..HEAD | sed 's/^/* /' >> diff.md
|
||||
- name: Release Nightly
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
body_path: diff.md
|
||||
prerelease: true
|
||||
|
||||
10
.github/workflows/nix-ci.yml
vendored
10
.github/workflows/nix-ci.yml
vendored
@@ -110,14 +110,6 @@ jobs:
|
||||
# https://github.com/netlify/cli/issues/1809
|
||||
cp -r --dereference ./result ./dist
|
||||
if: matrix.name == 'Nix Linux'
|
||||
- name: Check manual for broken links
|
||||
id: lychee
|
||||
uses: lycheeverse/lychee-action@v1.9.0
|
||||
with:
|
||||
fail: false # report errors but do not block CI on temporary failures
|
||||
# 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: Rebuild Nix Store Cache
|
||||
run: |
|
||||
rm -rf nix-store-cache || true
|
||||
@@ -129,7 +121,7 @@ jobs:
|
||||
python3 -c 'import base64; print("alias="+base64.urlsafe_b64encode(bytes.fromhex("${{github.sha}}")).decode("utf-8").rstrip("="))' >> "$GITHUB_OUTPUT"
|
||||
echo "message=`git log -1 --pretty=format:"%s"`" >> "$GITHUB_OUTPUT"
|
||||
- name: Publish manual to Netlify
|
||||
uses: nwtgck/actions-netlify@v2.0
|
||||
uses: nwtgck/actions-netlify@v3.0
|
||||
id: publish-manual
|
||||
with:
|
||||
publish-dir: ./dist
|
||||
|
||||
10
.github/workflows/pr-release.yml
vendored
10
.github/workflows/pr-release.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
- name: Download artifact from the previous workflow.
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
id: download-artifact
|
||||
uses: dawidd6/action-download-artifact@v2 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
uses: dawidd6/action-download-artifact@v6 # https://github.com/marketplace/actions/download-workflow-artifact
|
||||
with:
|
||||
run_id: ${{ github.event.workflow_run.id }}
|
||||
path: artifacts
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
- name: Release
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
|
||||
- name: Report release status
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
await github.rest.repos.createCommitStatus({
|
||||
@@ -111,7 +111,7 @@ jobs:
|
||||
|
||||
- name: 'Setup jq'
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: dcarbone/install-jq-action@v1.0.1
|
||||
uses: dcarbone/install-jq-action@v2.1.0
|
||||
|
||||
# Check that the most recently nightly coincides with 'git merge-base HEAD master'
|
||||
- name: Check merge-base and nightly-testing-YYYY-MM-DD
|
||||
@@ -208,7 +208,7 @@ jobs:
|
||||
|
||||
- name: Report mathlib base
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true' }}
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const description =
|
||||
|
||||
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v8
|
||||
- uses: actions/stale@v9
|
||||
with:
|
||||
days-before-stale: -1
|
||||
days-before-pr-stale: 30
|
||||
|
||||
310
RELEASES.md
310
RELEASES.md
@@ -21,7 +21,315 @@ Release candidate, release notes will be copied from the branch `releases/v4.14.
|
||||
v4.13.0
|
||||
----------
|
||||
|
||||
Release candidate, release notes will be copied from the branch `releases/v4.13.0` once completed.
|
||||
**Full Changelog**: https://github.com/leanprover/lean4/compare/v4.12.0...v4.13.0
|
||||
|
||||
### Language features, tactics, and metaprograms
|
||||
|
||||
* `structure` command
|
||||
* [#5511](https://github.com/leanprover/lean4/pull/5511) allows structure parents to be type synonyms.
|
||||
* [#5531](https://github.com/leanprover/lean4/pull/5531) allows default values for structure fields to be noncomputable.
|
||||
|
||||
* `rfl` and `apply_rfl` tactics
|
||||
* [#3714](https://github.com/leanprover/lean4/pull/3714), [#3718](https://github.com/leanprover/lean4/pull/3718) improve the `rfl` tactic and give better error messages.
|
||||
* [#3772](https://github.com/leanprover/lean4/pull/3772) makes `rfl` no longer use kernel defeq for ground terms.
|
||||
* [#5329](https://github.com/leanprover/lean4/pull/5329) tags `Iff.refl` with `@[refl]` (@Parcly-Taxel)
|
||||
* [#5359](https://github.com/leanprover/lean4/pull/5359) ensures that the `rfl` tactic tries `Iff.rfl` (@Parcly-Taxel)
|
||||
|
||||
* `unfold` tactic
|
||||
* [#4834](https://github.com/leanprover/lean4/pull/4834) let `unfold` do zeta-delta reduction of local definitions, incorporating functionality of the Mathlib `unfold_let` tactic.
|
||||
|
||||
* `omega` tactic
|
||||
* [#5382](https://github.com/leanprover/lean4/pull/5382) fixes spurious error in [#5315](https://github.com/leanprover/lean4/issues/5315)
|
||||
* [#5523](https://github.com/leanprover/lean4/pull/5523) supports `Int.toNat`
|
||||
|
||||
* `simp` tactic
|
||||
* [#5479](https://github.com/leanprover/lean4/pull/5479) lets `simp` apply rules with higher-order patterns.
|
||||
|
||||
* `induction` tactic
|
||||
* [#5494](https://github.com/leanprover/lean4/pull/5494) fixes `induction`’s "pre-tactic" block to always be indented, avoiding unintended uses of it.
|
||||
|
||||
* `ac_nf` tactic
|
||||
* [#5524](https://github.com/leanprover/lean4/pull/5524) adds `ac_nf`, a counterpart to `ac_rfl`, for normalizing expressions with respect to associativity and commutativity. Tests it with `BitVec` expressions.
|
||||
|
||||
* `bv_decide`
|
||||
* [#5211](https://github.com/leanprover/lean4/pull/5211) makes `extractLsb'` the primitive `bv_decide` understands, rather than `extractLsb` (@alexkeizer)
|
||||
* [#5365](https://github.com/leanprover/lean4/pull/5365) adds `bv_decide` diagnoses.
|
||||
* [#5375](https://github.com/leanprover/lean4/pull/5375) adds `bv_decide` normalization rules for `ofBool (a.getLsbD i)` and `ofBool a[i]` (@alexkeizer)
|
||||
* [#5423](https://github.com/leanprover/lean4/pull/5423) enhances the rewriting rules of `bv_decide`
|
||||
* [#5433](https://github.com/leanprover/lean4/pull/5433) presents the `bv_decide` counterexample at the API
|
||||
* [#5484](https://github.com/leanprover/lean4/pull/5484) handles `BitVec.ofNat` with `Nat` fvars in `bv_decide`
|
||||
* [#5506](https://github.com/leanprover/lean4/pull/5506), [#5507](https://github.com/leanprover/lean4/pull/5507) add `bv_normalize` rules.
|
||||
* [#5568](https://github.com/leanprover/lean4/pull/5568) generalize the `bv_normalize` pipeline to support more general preprocessing passes
|
||||
* [#5573](https://github.com/leanprover/lean4/pull/5573) gets `bv_normalize` up-to-date with the current `BitVec` rewrites
|
||||
* Cleanups: [#5408](https://github.com/leanprover/lean4/pull/5408), [#5493](https://github.com/leanprover/lean4/pull/5493), [#5578](https://github.com/leanprover/lean4/pull/5578)
|
||||
|
||||
|
||||
* Elaboration improvements
|
||||
* [#5266](https://github.com/leanprover/lean4/pull/5266) preserve order of overapplied arguments in `elab_as_elim` procedure.
|
||||
* [#5510](https://github.com/leanprover/lean4/pull/5510) generalizes `elab_as_elim` to allow arbitrary motive applications.
|
||||
* [#5283](https://github.com/leanprover/lean4/pull/5283), [#5512](https://github.com/leanprover/lean4/pull/5512) refine how named arguments suppress explicit arguments. Breaking change: some previously omitted explicit arguments may need explicit `_` arguments now.
|
||||
* [#5376](https://github.com/leanprover/lean4/pull/5376) modifies projection instance binder info for instances, making parameters that are instance implicit in the type be implicit.
|
||||
* [#5402](https://github.com/leanprover/lean4/pull/5402) localizes universe metavariable errors to `let` bindings and `fun` binders if possible. Makes "cannot synthesize metavariable" errors take precedence over unsolved universe level errors.
|
||||
* [#5419](https://github.com/leanprover/lean4/pull/5419) must not reduce `ite` in the discriminant of `match`-expression when reducibility setting is `.reducible`
|
||||
* [#5474](https://github.com/leanprover/lean4/pull/5474) have autoparams report parameter/field on failure
|
||||
* [#5530](https://github.com/leanprover/lean4/pull/5530) makes automatic instance names about types with hygienic names be hygienic.
|
||||
|
||||
* Deriving handlers
|
||||
* [#5432](https://github.com/leanprover/lean4/pull/5432) makes `Repr` deriving instance handle explicit type parameters
|
||||
|
||||
* Functional induction
|
||||
* [#5364](https://github.com/leanprover/lean4/pull/5364) adds more equalities in context, more careful cleanup.
|
||||
|
||||
* Linters
|
||||
* [#5335](https://github.com/leanprover/lean4/pull/5335) fixes the unused variables linter complaining about match/tactic combinations
|
||||
* [#5337](https://github.com/leanprover/lean4/pull/5337) fixes the unused variables linter complaining about some wildcard patterns
|
||||
|
||||
* Other fixes
|
||||
* [#4768](https://github.com/leanprover/lean4/pull/4768) fixes a parse error when `..` appears with a `.` on the next line
|
||||
|
||||
* Metaprogramming
|
||||
* [#3090](https://github.com/leanprover/lean4/pull/3090) handles level parameters in `Meta.evalExpr` (@eric-wieser)
|
||||
* [#5401](https://github.com/leanprover/lean4/pull/5401) instance for `Inhabited (TacticM α)` (@alexkeizer)
|
||||
* [#5412](https://github.com/leanprover/lean4/pull/5412) expose Kernel.check for debugging purposes
|
||||
* [#5556](https://github.com/leanprover/lean4/pull/5556) improves the "invalid projection" type inference error in `inferType`.
|
||||
* [#5587](https://github.com/leanprover/lean4/pull/5587) allows `MVarId.assertHypotheses` to set `BinderInfo` and `LocalDeclKind`.
|
||||
* [#5588](https://github.com/leanprover/lean4/pull/5588) adds `MVarId.tryClearMany'`, a variant of `MVarId.tryClearMany`.
|
||||
|
||||
|
||||
|
||||
### Language server, widgets, and IDE extensions
|
||||
|
||||
* [#5205](https://github.com/leanprover/lean4/pull/5205) decreases the latency of auto-completion in tactic blocks.
|
||||
* [#5237](https://github.com/leanprover/lean4/pull/5237) fixes symbol occurrence highlighting in VS Code not highlighting occurrences when moving the text cursor into the identifier from the right.
|
||||
* [#5257](https://github.com/leanprover/lean4/pull/5257) fixes several instances of incorrect auto-completions being reported.
|
||||
* [#5299](https://github.com/leanprover/lean4/pull/5299) allows auto-completion to report completions for global identifiers when the elaborator fails to provide context-specific auto-completions.
|
||||
* [#5312](https://github.com/leanprover/lean4/pull/5312) fixes the server breaking when changing whitespace after the module header.
|
||||
* [#5322](https://github.com/leanprover/lean4/pull/5322) fixes several instances of auto-completion reporting non-existent namespaces.
|
||||
* [#5428](https://github.com/leanprover/lean4/pull/5428) makes sure to always report some recent file range as progress when waiting for elaboration.
|
||||
|
||||
|
||||
### Pretty printing
|
||||
|
||||
* [#4979](https://github.com/leanprover/lean4/pull/4979) make pretty printer escape identifiers that are tokens.
|
||||
* [#5389](https://github.com/leanprover/lean4/pull/5389) makes formatter use the current token table.
|
||||
* [#5513](https://github.com/leanprover/lean4/pull/5513) use breakable instead of unbreakable whitespace when formatting tokens.
|
||||
|
||||
|
||||
### Library
|
||||
|
||||
* [#5222](https://github.com/leanprover/lean4/pull/5222) reduces allocations in `Json.compress`.
|
||||
* [#5231](https://github.com/leanprover/lean4/pull/5231) upstreams `Zero` and `NeZero`
|
||||
* [#5292](https://github.com/leanprover/lean4/pull/5292) refactors `Lean.Elab.Deriving.FromToJson` (@arthur-adjedj)
|
||||
* [#5415](https://github.com/leanprover/lean4/pull/5415) implements `Repr Empty` (@TomasPuverle)
|
||||
* [#5421](https://github.com/leanprover/lean4/pull/5421) implements `To/FromJSON Empty` (@TomasPuverle)
|
||||
|
||||
* Logic
|
||||
* [#5263](https://github.com/leanprover/lean4/pull/5263) allows simplifying `dite_not`/`decide_not` with only `Decidable (¬p)`.
|
||||
* [#5268](https://github.com/leanprover/lean4/pull/5268) fixes binders on `ite_eq_left_iff`
|
||||
* [#5284](https://github.com/leanprover/lean4/pull/5284) turns off `Inhabited (Sum α β)` instances
|
||||
* [#5355](https://github.com/leanprover/lean4/pull/5355) adds simp lemmas for `LawfulBEq`
|
||||
* [#5374](https://github.com/leanprover/lean4/pull/5374) add `Nonempty` instances for products, allowing more `partial` functions to elaborate successfully
|
||||
* [#5447](https://github.com/leanprover/lean4/pull/5447) updates Pi instance names
|
||||
* [#5454](https://github.com/leanprover/lean4/pull/5454) makes some instance arguments implicit
|
||||
* [#5456](https://github.com/leanprover/lean4/pull/5456) adds `heq_comm`
|
||||
* [#5529](https://github.com/leanprover/lean4/pull/5529) moves `@[simp]` from `exists_prop'` to `exists_prop`
|
||||
|
||||
* `Bool`
|
||||
* [#5228](https://github.com/leanprover/lean4/pull/5228) fills gaps in Bool lemmas
|
||||
* [#5332](https://github.com/leanprover/lean4/pull/5332) adds notation `^^` for Bool.xor
|
||||
* [#5351](https://github.com/leanprover/lean4/pull/5351) removes `_root_.and` (and or/not/xor) and instead exports/uses `Bool.and` (etc.).
|
||||
|
||||
* `BitVec`
|
||||
* [#5240](https://github.com/leanprover/lean4/pull/5240) removes BitVec simps with complicated RHS
|
||||
* [#5247](https://github.com/leanprover/lean4/pull/5247) `BitVec.getElem_zeroExtend`
|
||||
* [#5248](https://github.com/leanprover/lean4/pull/5248) simp lemmas for BitVec, improving confluence
|
||||
* [#5249](https://github.com/leanprover/lean4/pull/5249) removes `@[simp]` from some BitVec lemmas
|
||||
* [#5252](https://github.com/leanprover/lean4/pull/5252) changes `BitVec.intMin/Max` from abbrev to def
|
||||
* [#5278](https://github.com/leanprover/lean4/pull/5278) adds `BitVec.getElem_truncate` (@tobiasgrosser)
|
||||
* [#5281](https://github.com/leanprover/lean4/pull/5281) adds udiv/umod bitblasting for `bv_decide` (@bollu)
|
||||
* [#5297](https://github.com/leanprover/lean4/pull/5297) `BitVec` unsigned order theoretic results
|
||||
* [#5313](https://github.com/leanprover/lean4/pull/5313) adds more basic BitVec ordering theory for UInt
|
||||
* [#5314](https://github.com/leanprover/lean4/pull/5314) adds `toNat_sub_of_le` (@bollu)
|
||||
* [#5357](https://github.com/leanprover/lean4/pull/5357) adds `BitVec.truncate` lemmas
|
||||
* [#5358](https://github.com/leanprover/lean4/pull/5358) introduces `BitVec.setWidth` to unify zeroExtend and truncate (@tobiasgrosser)
|
||||
* [#5361](https://github.com/leanprover/lean4/pull/5361) some BitVec GetElem lemmas
|
||||
* [#5385](https://github.com/leanprover/lean4/pull/5385) adds `BitVec.ofBool_[and|or|xor]_ofBool` theorems (@tobiasgrosser)
|
||||
* [#5404](https://github.com/leanprover/lean4/pull/5404) more of `BitVec.getElem_*` (@tobiasgrosser)
|
||||
* [#5410](https://github.com/leanprover/lean4/pull/5410) BitVec analogues of `Nat.{mul_two, two_mul, mul_succ, succ_mul}` (@bollu)
|
||||
* [#5411](https://github.com/leanprover/lean4/pull/5411) `BitVec.toNat_{add,sub,mul_of_lt}` for BitVector non-overflow reasoning (@bollu)
|
||||
* [#5413](https://github.com/leanprover/lean4/pull/5413) adds `_self`, `_zero`, and `_allOnes` for `BitVec.[and|or|xor]` (@tobiasgrosser)
|
||||
* [#5416](https://github.com/leanprover/lean4/pull/5416) adds LawCommIdentity + IdempotentOp for `BitVec.[and|or|xor]` (@tobiasgrosser)
|
||||
* [#5418](https://github.com/leanprover/lean4/pull/5418) decidable quantifers for BitVec
|
||||
* [#5450](https://github.com/leanprover/lean4/pull/5450) adds `BitVec.toInt_[intMin|neg|neg_of_ne_intMin]` (@tobiasgrosser)
|
||||
* [#5459](https://github.com/leanprover/lean4/pull/5459) missing BitVec lemmas
|
||||
* [#5469](https://github.com/leanprover/lean4/pull/5469) adds `BitVec.[not_not, allOnes_shiftLeft_or_shiftLeft, allOnes_shiftLeft_and_shiftLeft]` (@luisacicolini)
|
||||
* [#5478](https://github.com/leanprover/lean4/pull/5478) adds `BitVec.(shiftLeft_add_distrib, shiftLeft_ushiftRight)` (@luisacicolini)
|
||||
* [#5487](https://github.com/leanprover/lean4/pull/5487) adds `sdiv_eq`, `smod_eq` to allow `sdiv`/`smod` bitblasting (@bollu)
|
||||
* [#5491](https://github.com/leanprover/lean4/pull/5491) adds `BitVec.toNat_[abs|sdiv|smod]` (@tobiasgrosser)
|
||||
* [#5492](https://github.com/leanprover/lean4/pull/5492) `BitVec.(not_sshiftRight, not_sshiftRight_not, getMsb_not, msb_not)` (@luisacicolini)
|
||||
* [#5499](https://github.com/leanprover/lean4/pull/5499) `BitVec.Lemmas` - drop non-terminal simps (@tobiasgrosser)
|
||||
* [#5505](https://github.com/leanprover/lean4/pull/5505) unsimps `BitVec.divRec_succ'`
|
||||
* [#5508](https://github.com/leanprover/lean4/pull/5508) adds `BitVec.getElem_[add|add_add_bool|mul|rotateLeft|rotateRight…` (@tobiasgrosser)
|
||||
* [#5554](https://github.com/leanprover/lean4/pull/5554) adds `Bitvec.[add, sub, mul]_eq_xor` and `width_one_cases` (@luisacicolini)
|
||||
|
||||
* `List`
|
||||
* [#5242](https://github.com/leanprover/lean4/pull/5242) improve naming for `List.mergeSort` lemmas
|
||||
* [#5302](https://github.com/leanprover/lean4/pull/5302) provide `mergeSort` comparator autoParam
|
||||
* [#5373](https://github.com/leanprover/lean4/pull/5373) fix name of `List.length_mergeSort`
|
||||
* [#5377](https://github.com/leanprover/lean4/pull/5377) upstream `map_mergeSort`
|
||||
* [#5378](https://github.com/leanprover/lean4/pull/5378) modify signature of lemmas about `mergeSort`
|
||||
* [#5245](https://github.com/leanprover/lean4/pull/5245) avoid importing `List.Basic` without List.Impl
|
||||
* [#5260](https://github.com/leanprover/lean4/pull/5260) review of List API
|
||||
* [#5264](https://github.com/leanprover/lean4/pull/5264) review of List API
|
||||
* [#5269](https://github.com/leanprover/lean4/pull/5269) remove HashMap's duplicated Pairwise and Sublist
|
||||
* [#5271](https://github.com/leanprover/lean4/pull/5271) remove @[simp] from `List.head_mem` and similar
|
||||
* [#5273](https://github.com/leanprover/lean4/pull/5273) lemmas about `List.attach`
|
||||
* [#5275](https://github.com/leanprover/lean4/pull/5275) reverse direction of `List.tail_map`
|
||||
* [#5277](https://github.com/leanprover/lean4/pull/5277) more `List.attach` lemmas
|
||||
* [#5285](https://github.com/leanprover/lean4/pull/5285) `List.count` lemmas
|
||||
* [#5287](https://github.com/leanprover/lean4/pull/5287) use boolean predicates in `List.filter`
|
||||
* [#5289](https://github.com/leanprover/lean4/pull/5289) `List.mem_ite_nil_left` and analogues
|
||||
* [#5293](https://github.com/leanprover/lean4/pull/5293) cleanup of `List.findIdx` / `List.take` lemmas
|
||||
* [#5294](https://github.com/leanprover/lean4/pull/5294) switch primes on `List.getElem_take`
|
||||
* [#5300](https://github.com/leanprover/lean4/pull/5300) more `List.findIdx` theorems
|
||||
* [#5310](https://github.com/leanprover/lean4/pull/5310) fix `List.all/any` lemmas
|
||||
* [#5311](https://github.com/leanprover/lean4/pull/5311) fix `List.countP` lemmas
|
||||
* [#5316](https://github.com/leanprover/lean4/pull/5316) `List.tail` lemma
|
||||
* [#5331](https://github.com/leanprover/lean4/pull/5331) fix implicitness of `List.getElem_mem`
|
||||
* [#5350](https://github.com/leanprover/lean4/pull/5350) `List.replicate` lemmas
|
||||
* [#5352](https://github.com/leanprover/lean4/pull/5352) `List.attachWith` lemmas
|
||||
* [#5353](https://github.com/leanprover/lean4/pull/5353) `List.head_mem_head?`
|
||||
* [#5360](https://github.com/leanprover/lean4/pull/5360) lemmas about `List.tail`
|
||||
* [#5391](https://github.com/leanprover/lean4/pull/5391) review of `List.erase` / `List.find` lemmas
|
||||
* [#5392](https://github.com/leanprover/lean4/pull/5392) `List.fold` / `attach` lemmas
|
||||
* [#5393](https://github.com/leanprover/lean4/pull/5393) `List.fold` relators
|
||||
* [#5394](https://github.com/leanprover/lean4/pull/5394) lemmas about `List.maximum?`
|
||||
* [#5403](https://github.com/leanprover/lean4/pull/5403) theorems about `List.toArray`
|
||||
* [#5405](https://github.com/leanprover/lean4/pull/5405) reverse direction of `List.set_map`
|
||||
* [#5448](https://github.com/leanprover/lean4/pull/5448) add lemmas about `List.IsPrefix` (@Command-Master)
|
||||
* [#5460](https://github.com/leanprover/lean4/pull/5460) missing `List.set_replicate_self`
|
||||
* [#5518](https://github.com/leanprover/lean4/pull/5518) rename `List.maximum?` to `max?`
|
||||
* [#5519](https://github.com/leanprover/lean4/pull/5519) upstream `List.fold` lemmas
|
||||
* [#5520](https://github.com/leanprover/lean4/pull/5520) restore `@[simp]` on `List.getElem_mem` etc.
|
||||
* [#5521](https://github.com/leanprover/lean4/pull/5521) List simp fixes
|
||||
* [#5550](https://github.com/leanprover/lean4/pull/5550) `List.unattach` and simp lemmas
|
||||
* [#5594](https://github.com/leanprover/lean4/pull/5594) induction-friendly `List.min?_cons`
|
||||
|
||||
* `Array`
|
||||
* [#5246](https://github.com/leanprover/lean4/pull/5246) cleanup imports of Array.Lemmas
|
||||
* [#5255](https://github.com/leanprover/lean4/pull/5255) split Init.Data.Array.Lemmas for better bootstrapping
|
||||
* [#5288](https://github.com/leanprover/lean4/pull/5288) rename `Array.data` to `Array.toList`
|
||||
* [#5303](https://github.com/leanprover/lean4/pull/5303) cleanup of `List.getElem_append` variants
|
||||
* [#5304](https://github.com/leanprover/lean4/pull/5304) `Array.not_mem_empty`
|
||||
* [#5400](https://github.com/leanprover/lean4/pull/5400) reorganization in Array/Basic
|
||||
* [#5420](https://github.com/leanprover/lean4/pull/5420) make `Array` functions either semireducible or use structural recursion
|
||||
* [#5422](https://github.com/leanprover/lean4/pull/5422) refactor `DecidableEq (Array α)`
|
||||
* [#5452](https://github.com/leanprover/lean4/pull/5452) refactor of Array
|
||||
* [#5458](https://github.com/leanprover/lean4/pull/5458) cleanup of Array docstrings after refactor
|
||||
* [#5461](https://github.com/leanprover/lean4/pull/5461) restore `@[simp]` on `Array.swapAt!_def`
|
||||
* [#5465](https://github.com/leanprover/lean4/pull/5465) improve Array GetElem lemmas
|
||||
* [#5466](https://github.com/leanprover/lean4/pull/5466) `Array.foldX` lemmas
|
||||
* [#5472](https://github.com/leanprover/lean4/pull/5472) @[simp] lemmas about `List.toArray`
|
||||
* [#5485](https://github.com/leanprover/lean4/pull/5485) reverse simp direction for `toArray_concat`
|
||||
* [#5514](https://github.com/leanprover/lean4/pull/5514) `Array.eraseReps`
|
||||
* [#5515](https://github.com/leanprover/lean4/pull/5515) upstream `Array.qsortOrd`
|
||||
* [#5516](https://github.com/leanprover/lean4/pull/5516) upstream `Subarray.empty`
|
||||
* [#5526](https://github.com/leanprover/lean4/pull/5526) fix name of `Array.length_toList`
|
||||
* [#5527](https://github.com/leanprover/lean4/pull/5527) reduce use of deprecated lemmas in Array
|
||||
* [#5534](https://github.com/leanprover/lean4/pull/5534) cleanup of Array GetElem lemmas
|
||||
* [#5536](https://github.com/leanprover/lean4/pull/5536) fix `Array.modify` lemmas
|
||||
* [#5551](https://github.com/leanprover/lean4/pull/5551) upstream `Array.flatten` lemmas
|
||||
* [#5552](https://github.com/leanprover/lean4/pull/5552) switch obvious cases of array "bang"`[]!` indexing to rely on hypothesis (@TomasPuverle)
|
||||
* [#5577](https://github.com/leanprover/lean4/pull/5577) add missing simp to `Array.size_feraseIdx`
|
||||
* [#5586](https://github.com/leanprover/lean4/pull/5586) `Array/Option.unattach`
|
||||
|
||||
* `Option`
|
||||
* [#5272](https://github.com/leanprover/lean4/pull/5272) remove @[simp] from `Option.pmap/pbind` and add simp lemmas
|
||||
* [#5307](https://github.com/leanprover/lean4/pull/5307) restoring Option simp confluence
|
||||
* [#5354](https://github.com/leanprover/lean4/pull/5354) remove @[simp] from `Option.bind_map`
|
||||
* [#5532](https://github.com/leanprover/lean4/pull/5532) `Option.attach`
|
||||
* [#5539](https://github.com/leanprover/lean4/pull/5539) fix explicitness of `Option.mem_toList`
|
||||
|
||||
* `Nat`
|
||||
* [#5241](https://github.com/leanprover/lean4/pull/5241) add @[simp] to `Nat.add_eq_zero_iff`
|
||||
* [#5261](https://github.com/leanprover/lean4/pull/5261) Nat bitwise lemmas
|
||||
* [#5262](https://github.com/leanprover/lean4/pull/5262) `Nat.testBit_add_one` should not be a global simp lemma
|
||||
* [#5267](https://github.com/leanprover/lean4/pull/5267) protect some Nat bitwise theorems
|
||||
* [#5305](https://github.com/leanprover/lean4/pull/5305) rename Nat bitwise lemmas
|
||||
* [#5306](https://github.com/leanprover/lean4/pull/5306) add `Nat.self_sub_mod` lemma
|
||||
* [#5503](https://github.com/leanprover/lean4/pull/5503) restore @[simp] to upstreamed `Nat.lt_off_iff`
|
||||
|
||||
* `Int`
|
||||
* [#5301](https://github.com/leanprover/lean4/pull/5301) rename `Int.div/mod` to `Int.tdiv/tmod`
|
||||
* [#5320](https://github.com/leanprover/lean4/pull/5320) add `ediv_nonneg_of_nonpos_of_nonpos` to DivModLemmas (@sakehl)
|
||||
|
||||
* `Fin`
|
||||
* [#5250](https://github.com/leanprover/lean4/pull/5250) missing lemma about `Fin.ofNat'`
|
||||
* [#5356](https://github.com/leanprover/lean4/pull/5356) `Fin.ofNat'` uses `NeZero`
|
||||
* [#5379](https://github.com/leanprover/lean4/pull/5379) remove some @[simp]s from Fin lemmas
|
||||
* [#5380](https://github.com/leanprover/lean4/pull/5380) missing Fin @[simp] lemmas
|
||||
|
||||
* `HashMap`
|
||||
* [#5244](https://github.com/leanprover/lean4/pull/5244) (`DHashMap`|`HashMap`|`HashSet`).(`getKey?`|`getKey`|`getKey!`|`getKeyD`)
|
||||
* [#5362](https://github.com/leanprover/lean4/pull/5362) remove the last use of `Lean.(HashSet|HashMap)`
|
||||
* [#5369](https://github.com/leanprover/lean4/pull/5369) `HashSet.ofArray`
|
||||
* [#5370](https://github.com/leanprover/lean4/pull/5370) `HashSet.partition`
|
||||
* [#5581](https://github.com/leanprover/lean4/pull/5581) `Singleton`/`Insert`/`Union` instances for `HashMap`/`Set`
|
||||
* [#5582](https://github.com/leanprover/lean4/pull/5582) `HashSet.all`/`any`
|
||||
* [#5590](https://github.com/leanprover/lean4/pull/5590) adding `Insert`/`Singleton`/`Union` instances for `HashMap`/`Set.Raw`
|
||||
* [#5591](https://github.com/leanprover/lean4/pull/5591) `HashSet.Raw.all/any`
|
||||
|
||||
* `Monads`
|
||||
* [#5463](https://github.com/leanprover/lean4/pull/5463) upstream some monad lemmas
|
||||
* [#5464](https://github.com/leanprover/lean4/pull/5464) adjust simp attributes on monad lemmas
|
||||
* [#5522](https://github.com/leanprover/lean4/pull/5522) more monadic simp lemmas
|
||||
|
||||
* Simp lemma cleanup
|
||||
* [#5251](https://github.com/leanprover/lean4/pull/5251) remove redundant simp annotations
|
||||
* [#5253](https://github.com/leanprover/lean4/pull/5253) remove Int simp lemmas that can't fire
|
||||
* [#5254](https://github.com/leanprover/lean4/pull/5254) variables appearing on both sides of an iff should be implicit
|
||||
* [#5381](https://github.com/leanprover/lean4/pull/5381) cleaning up redundant simp lemmas
|
||||
|
||||
|
||||
### Compiler, runtime, and FFI
|
||||
|
||||
* [#4685](https://github.com/leanprover/lean4/pull/4685) fixes a typo in the C `run_new_frontend` signature
|
||||
* [#4729](https://github.com/leanprover/lean4/pull/4729) has IR checker suggest using `noncomputable`
|
||||
* [#5143](https://github.com/leanprover/lean4/pull/5143) adds a shared library for Lake
|
||||
* [#5437](https://github.com/leanprover/lean4/pull/5437) removes (syntactically) duplicate imports (@euprunin)
|
||||
* [#5462](https://github.com/leanprover/lean4/pull/5462) updates `src/lake/lakefile.toml` to the adjusted Lake build process
|
||||
* [#5541](https://github.com/leanprover/lean4/pull/5541) removes new shared libs before build to better support Windows
|
||||
* [#5558](https://github.com/leanprover/lean4/pull/5558) make `lean.h` compile with MSVC (@kant2002)
|
||||
* [#5564](https://github.com/leanprover/lean4/pull/5564) removes non-conforming size-0 arrays (@eric-wieser)
|
||||
|
||||
|
||||
### Lake
|
||||
* Reservoir build cache. Lake will now attempt to fetch a pre-built copy of the package from Reservoir before building it. This is only enabled for packages in the leanprover or leanprover-community organizations on versions indexed by Reservoir. Users can force Lake to build packages from the source by passing --no-cache on the CLI or by setting the LAKE_NO_CACHE environment variable to true. [#5486](https://github.com/leanprover/lean4/pull/5486), [#5572](https://github.com/leanprover/lean4/pull/5572), [#5583](https://github.com/leanprover/lean4/pull/5583), [#5600](https://github.com/leanprover/lean4/pull/5600), [#5641](https://github.com/leanprover/lean4/pull/5641), [#5642](https://github.com/leanprover/lean4/pull/5642).
|
||||
* [#5504](https://github.com/leanprover/lean4/pull/5504) lake new and lake init now produce TOML configurations by default.
|
||||
* [#5878](https://github.com/leanprover/lean4/pull/5878) fixes a serious issue where Lake would delete path dependencies when attempting to cleanup a dependency required with an incorrect name.
|
||||
|
||||
* **Breaking changes**
|
||||
* [#5641](https://github.com/leanprover/lean4/pull/5641) A Lake build of target within a package will no longer build a package's dependencies package-level extra target dependencies. At the technical level, a package's extraDep facet no longer transitively builds its dependencies’ extraDep facets (which include their extraDepTargets).
|
||||
|
||||
### Documentation fixes
|
||||
|
||||
* [#3918](https://github.com/leanprover/lean4/pull/3918) `@[builtin_doc]` attribute (@digama0)
|
||||
* [#4305](https://github.com/leanprover/lean4/pull/4305) explains the borrow syntax (@eric-wieser)
|
||||
* [#5349](https://github.com/leanprover/lean4/pull/5349) adds documentation for `groupBy.loop` (@vihdzp)
|
||||
* [#5473](https://github.com/leanprover/lean4/pull/5473) fixes typo in `BitVec.mul` docstring (@llllvvuu)
|
||||
* [#5476](https://github.com/leanprover/lean4/pull/5476) fixes typos in `Lean.MetavarContext`
|
||||
* [#5481](https://github.com/leanprover/lean4/pull/5481) removes mention of `Lean.withSeconds` (@alexkeizer)
|
||||
* [#5497](https://github.com/leanprover/lean4/pull/5497) updates documentation and tests for `toUIntX` functions (@TomasPuverle)
|
||||
* [#5087](https://github.com/leanprover/lean4/pull/5087) mentions that `inferType` does not ensure type correctness
|
||||
* Many fixes to spelling across the doc-strings, (@euprunin): [#5425](https://github.com/leanprover/lean4/pull/5425) [#5426](https://github.com/leanprover/lean4/pull/5426) [#5427](https://github.com/leanprover/lean4/pull/5427) [#5430](https://github.com/leanprover/lean4/pull/5430) [#5431](https://github.com/leanprover/lean4/pull/5431) [#5434](https://github.com/leanprover/lean4/pull/5434) [#5435](https://github.com/leanprover/lean4/pull/5435) [#5436](https://github.com/leanprover/lean4/pull/5436) [#5438](https://github.com/leanprover/lean4/pull/5438) [#5439](https://github.com/leanprover/lean4/pull/5439) [#5440](https://github.com/leanprover/lean4/pull/5440) [#5599](https://github.com/leanprover/lean4/pull/5599)
|
||||
|
||||
### Changes to CI
|
||||
|
||||
* [#5343](https://github.com/leanprover/lean4/pull/5343) allows addition of `release-ci` label via comment (@thorimur)
|
||||
* [#5344](https://github.com/leanprover/lean4/pull/5344) sets check level correctly during workflow (@thorimur)
|
||||
* [#5444](https://github.com/leanprover/lean4/pull/5444) Mathlib's `lean-pr-testing-NNNN` branches should use Batteries' `lean-pr-testing-NNNN` branches
|
||||
* [#5489](https://github.com/leanprover/lean4/pull/5489) commit `lake-manifest.json` when updating `lean-pr-testing` branches
|
||||
* [#5490](https://github.com/leanprover/lean4/pull/5490) use separate secrets for commenting and branching in `pr-release.yml`
|
||||
|
||||
v4.12.0
|
||||
----------
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
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).
|
||||
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](../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.
|
||||
We strongly suggest that new users instead follow the [Quickstart](../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
|
||||
------------
|
||||
|
||||
@@ -64,7 +64,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 ROOT/lib/glibc/libpthread_nonshared.a -Wl,--as-needed -Wl,-Bstatic -lgmp -lunwind -luv -lpthread -ldl -lrt -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 ROOT/lib/glibc/libpthread_nonshared.a -Wl,--as-needed -Wl,-Bstatic -lgmp -lunwind -luv -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 -luv -lpthread -ldl -lrt -Wl,--no-as-needed'"
|
||||
# do not set `LEAN_CC` for tests
|
||||
|
||||
@@ -17,6 +17,8 @@ set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description li
|
||||
set(LEAN_VERSION_STRING "${LEAN_VERSION_MAJOR}.${LEAN_VERSION_MINOR}.${LEAN_VERSION_PATCH}")
|
||||
if (LEAN_SPECIAL_VERSION_DESC)
|
||||
string(APPEND LEAN_VERSION_STRING "-${LEAN_SPECIAL_VERSION_DESC}")
|
||||
elseif (NOT LEAN_VERSION_IS_RELEASE)
|
||||
string(APPEND LEAN_VERSION_STRING "-pre")
|
||||
endif()
|
||||
|
||||
set(LEAN_PLATFORM_TARGET "" CACHE STRING "LLVM triple of the target platform")
|
||||
|
||||
@@ -861,16 +861,21 @@ theorem Exists.elim {α : Sort u} {p : α → Prop} {b : Prop}
|
||||
|
||||
/-! # Decidable -/
|
||||
|
||||
theorem decide_true_eq_true (h : Decidable True) : @decide True h = true :=
|
||||
@[simp] theorem decide_true (h : Decidable True) : @decide True h = true :=
|
||||
match h with
|
||||
| isTrue _ => rfl
|
||||
| isFalse h => False.elim <| h ⟨⟩
|
||||
|
||||
theorem decide_false_eq_false (h : Decidable False) : @decide False h = false :=
|
||||
@[simp] theorem decide_false (h : Decidable False) : @decide False h = false :=
|
||||
match h with
|
||||
| isFalse _ => rfl
|
||||
| isTrue h => False.elim h
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated decide_true (since := "2024-11-05")] abbrev decide_true_eq_true := decide_true
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated decide_false (since := "2024-11-05")] abbrev decide_false_eq_false := decide_false
|
||||
|
||||
/-- Similar to `decide`, but uses an explicit instance -/
|
||||
@[inline] def toBoolUsing {p : Prop} (d : Decidable p) : Bool :=
|
||||
decide (h := d)
|
||||
|
||||
@@ -866,6 +866,7 @@ def zip (as : Array α) (bs : Array β) : Array (α × β) :=
|
||||
def unzip (as : Array (α × β)) : Array α × Array β :=
|
||||
as.foldl (init := (#[], #[])) fun (as, bs) (a, b) => (as.push a, bs.push b)
|
||||
|
||||
@[deprecated partition (since := "2024-11-06")]
|
||||
def split (as : Array α) (p : α → Bool) : Array α × Array α :=
|
||||
as.foldl (init := (#[], #[])) fun (as, bs) a =>
|
||||
if p a then (as.push a, bs) else (as, bs.push a)
|
||||
|
||||
@@ -23,7 +23,7 @@ theorem foldlM_eq_foldlM_toList.aux [Monad m]
|
||||
· cases Nat.not_le_of_gt ‹_› (Nat.zero_add _ ▸ H)
|
||||
· rename_i i; rw [Nat.succ_add] at H
|
||||
simp [foldlM_eq_foldlM_toList.aux f arr i (j+1) H]
|
||||
rw (occs := .pos [2]) [← List.get_drop_eq_drop _ _ ‹_›]
|
||||
rw (occs := .pos [2]) [← List.getElem_cons_drop_succ_eq_drop ‹_›]
|
||||
rfl
|
||||
· rw [List.drop_of_length_le (Nat.ge_of_not_lt ‹_›)]; rfl
|
||||
|
||||
@@ -79,6 +79,17 @@ theorem foldr_eq_foldr_toList (f : α → β → β) (init : β) (arr : Array α
|
||||
rw [foldl_eq_foldl_toList]
|
||||
induction arr'.toList generalizing arr <;> simp [*]
|
||||
|
||||
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
|
||||
|
||||
@[simp] theorem append_nil (as : Array α) : as ++ #[] = as := by
|
||||
apply ext'; simp only [toList_append, toList_empty, List.append_nil]
|
||||
|
||||
@[simp] theorem nil_append (as : Array α) : #[] ++ as = as := by
|
||||
apply ext'; simp only [toList_append, toList_empty, List.nil_append]
|
||||
|
||||
@[simp] theorem append_assoc (as bs cs : Array α) : as ++ bs ++ cs = as ++ (bs ++ cs) := by
|
||||
apply ext'; simp only [toList_append, List.append_assoc]
|
||||
|
||||
@[simp] theorem appendList_eq_append
|
||||
(arr : Array α) (l : List α) : arr.appendList l = arr ++ l := rfl
|
||||
|
||||
|
||||
@@ -41,6 +41,6 @@ where
|
||||
getLit_eq (as : Array α) (i : Nat) (h₁ : as.size = n) (h₂ : i < n) : as.getLit i h₁ h₂ = getElem as.toList i ((id (α := as.toList.length = n) h₁) ▸ h₂) :=
|
||||
rfl
|
||||
go (i : Nat) (hi : i ≤ as.size) : toListLitAux as n hsz i hi (as.toList.drop i) = as.toList := by
|
||||
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.get_drop_eq_drop, *]
|
||||
induction i <;> simp only [List.drop, toListLitAux, getLit_eq, List.getElem_cons_drop_succ_eq_drop, *]
|
||||
|
||||
end Array
|
||||
|
||||
@@ -10,6 +10,7 @@ import Init.Data.List.Monadic
|
||||
import Init.Data.List.Range
|
||||
import Init.Data.List.Nat.TakeDrop
|
||||
import Init.Data.List.Nat.Modify
|
||||
import Init.Data.List.Nat.Erase
|
||||
import Init.Data.List.Monadic
|
||||
import Init.Data.List.OfFn
|
||||
import Init.Data.Array.Mem
|
||||
@@ -189,6 +190,151 @@ theorem foldl_toArray (f : β → α → β) (init : β) (l : List α) :
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp] theorem push_append_toArray {as : Array α} {a : α} {bs : List α} : as.push a ++ bs.toArray = as ++ (a ::bs).toArray := by
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[simp] theorem foldl_push {l : List α} {as : Array α} : l.foldl Array.push as = as ++ l.toArray := by
|
||||
induction l generalizing as <;> simp [*]
|
||||
|
||||
@[simp] theorem findSomeM?_toArray [Monad m] [LawfulMonad m] (f : α → m (Option β)) (l : List α) :
|
||||
l.toArray.findSomeM? f = l.findSomeM? f := by
|
||||
rw [Array.findSomeM?]
|
||||
simp only [bind_pure_comp, map_pure, forIn_toArray]
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp only [forIn_cons, LawfulMonad.bind_assoc, findSomeM?]
|
||||
congr
|
||||
ext1 (_|_) <;> simp [ih]
|
||||
|
||||
theorem findSomeRevM?_find_toArray [Monad m] [LawfulMonad m] (f : α → m (Option β)) (l : List α)
|
||||
(i : Nat) (h) :
|
||||
findSomeRevM?.find l.toArray f i h = (l.take i).reverse.findSomeM? f := by
|
||||
induction i generalizing l with
|
||||
| zero => simp [Array.findSomeRevM?.find.eq_def]
|
||||
| succ i ih =>
|
||||
rw [size_toArray] at h
|
||||
rw [Array.findSomeRevM?.find, take_succ, getElem?_eq_getElem (by omega)]
|
||||
simp only [ih, reverse_append]
|
||||
congr
|
||||
ext1 (_|_) <;> simp
|
||||
|
||||
-- This is not marked as `@[simp]` as later we simplify all occurrences of `findSomeRevM?`.
|
||||
theorem findSomeRevM?_toArray [Monad m] [LawfulMonad m] (f : α → m (Option β)) (l : List α) :
|
||||
l.toArray.findSomeRevM? f = l.reverse.findSomeM? f := by
|
||||
simp [Array.findSomeRevM?, findSomeRevM?_find_toArray]
|
||||
|
||||
-- This is not marked as `@[simp]` as later we simplify all occurrences of `findRevM?`.
|
||||
theorem findRevM?_toArray [Monad m] [LawfulMonad m] (f : α → m Bool) (l : List α) :
|
||||
l.toArray.findRevM? f = l.reverse.findM? f := by
|
||||
rw [Array.findRevM?, findSomeRevM?_toArray, findM?_eq_findSomeM?]
|
||||
|
||||
@[simp] theorem findM?_toArray [Monad m] [LawfulMonad m] (f : α → m Bool) (l : List α) :
|
||||
l.toArray.findM? f = l.findM? f := by
|
||||
rw [Array.findM?]
|
||||
simp only [bind_pure_comp, map_pure, forIn_toArray]
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons a l ih =>
|
||||
simp only [forIn_cons, LawfulMonad.bind_assoc, findM?]
|
||||
congr
|
||||
ext1 (_|_) <;> simp [ih]
|
||||
|
||||
@[simp] theorem findSome?_toArray (f : α → Option β) (l : List α) :
|
||||
l.toArray.findSome? f = l.findSome? f := by
|
||||
rw [Array.findSome?, ← findSomeM?_id, findSomeM?_toArray, Id.run]
|
||||
|
||||
@[simp] theorem find?_toArray (f : α → Bool) (l : List α) :
|
||||
l.toArray.find? f = l.find? f := by
|
||||
rw [Array.find?, ← findM?_id, findM?_toArray, Id.run]
|
||||
|
||||
theorem isPrefixOfAux_toArray_succ [BEq α] (l₁ l₂ : List α) (hle : l₁.length ≤ l₂.length) (i : Nat) :
|
||||
Array.isPrefixOfAux l₁.toArray l₂.toArray hle (i + 1) =
|
||||
Array.isPrefixOfAux l₁.tail.toArray l₂.tail.toArray (by simp; omega) i := by
|
||||
rw [Array.isPrefixOfAux]
|
||||
conv => rhs; rw [Array.isPrefixOfAux]
|
||||
simp only [size_toArray, getElem_toArray, Bool.if_false_right, length_tail, getElem_tail]
|
||||
split <;> rename_i h₁ <;> split <;> rename_i h₂
|
||||
· rw [isPrefixOfAux_toArray_succ]
|
||||
· omega
|
||||
· omega
|
||||
· rfl
|
||||
|
||||
theorem isPrefixOfAux_toArray_succ' [BEq α] (l₁ l₂ : List α) (hle : l₁.length ≤ l₂.length) (i : Nat) :
|
||||
Array.isPrefixOfAux l₁.toArray l₂.toArray hle (i + 1) =
|
||||
Array.isPrefixOfAux (l₁.drop (i+1)).toArray (l₂.drop (i+1)).toArray (by simp; omega) 0 := by
|
||||
induction i generalizing l₁ l₂ with
|
||||
| zero => simp [isPrefixOfAux_toArray_succ]
|
||||
| succ i ih =>
|
||||
rw [isPrefixOfAux_toArray_succ, ih]
|
||||
simp
|
||||
|
||||
theorem isPrefixOfAux_toArray_zero [BEq α] (l₁ l₂ : List α) (hle : l₁.length ≤ l₂.length) :
|
||||
Array.isPrefixOfAux l₁.toArray l₂.toArray hle 0 =
|
||||
l₁.isPrefixOf l₂ := by
|
||||
rw [Array.isPrefixOfAux]
|
||||
match l₁, l₂ with
|
||||
| [], _ => rw [dif_neg] <;> simp
|
||||
| _::_, [] => simp at hle
|
||||
| a::l₁, b::l₂ =>
|
||||
simp [isPrefixOf_cons₂, isPrefixOfAux_toArray_succ', isPrefixOfAux_toArray_zero]
|
||||
|
||||
@[simp] theorem isPrefixOf_toArray [BEq α] (l₁ l₂ : List α) :
|
||||
l₁.toArray.isPrefixOf l₂.toArray = l₁.isPrefixOf l₂ := by
|
||||
rw [Array.isPrefixOf]
|
||||
split <;> rename_i h
|
||||
· simp [isPrefixOfAux_toArray_zero]
|
||||
· simp only [Bool.false_eq]
|
||||
induction l₁ generalizing l₂ with
|
||||
| nil => simp at h
|
||||
| cons a l₁ ih =>
|
||||
cases l₂ with
|
||||
| nil => simp
|
||||
| cons b l₂ =>
|
||||
simp only [isPrefixOf_cons₂, Bool.and_eq_false_imp]
|
||||
intro w
|
||||
rw [ih]
|
||||
simp_all
|
||||
|
||||
theorem zipWithAux_toArray_succ (f : α → β → γ) (as : List α) (bs : List β) (i : Nat) (cs : Array γ) :
|
||||
zipWithAux f as.toArray bs.toArray (i + 1) cs = zipWithAux f as.tail.toArray bs.tail.toArray i cs := by
|
||||
rw [zipWithAux]
|
||||
conv => rhs; rw [zipWithAux]
|
||||
simp only [size_toArray, getElem_toArray, length_tail, getElem_tail]
|
||||
split <;> rename_i h₁
|
||||
· split <;> rename_i h₂
|
||||
· rw [dif_pos (by omega), dif_pos (by omega), zipWithAux_toArray_succ]
|
||||
· rw [dif_pos (by omega)]
|
||||
rw [dif_neg (by omega)]
|
||||
· rw [dif_neg (by omega)]
|
||||
|
||||
theorem zipWithAux_toArray_succ' (f : α → β → γ) (as : List α) (bs : List β) (i : Nat) (cs : Array γ) :
|
||||
zipWithAux f as.toArray bs.toArray (i + 1) cs = zipWithAux f (as.drop (i+1)).toArray (bs.drop (i+1)).toArray 0 cs := by
|
||||
induction i generalizing as bs cs with
|
||||
| zero => simp [zipWithAux_toArray_succ]
|
||||
| succ i ih =>
|
||||
rw [zipWithAux_toArray_succ, ih]
|
||||
simp
|
||||
|
||||
theorem zipWithAux_toArray_zero (f : α → β → γ) (as : List α) (bs : List β) (cs : Array γ) :
|
||||
zipWithAux f as.toArray bs.toArray 0 cs = cs ++ (List.zipWith f as bs).toArray := by
|
||||
rw [Array.zipWithAux]
|
||||
match as, bs with
|
||||
| [], _ => simp
|
||||
| _, [] => simp
|
||||
| a :: as, b :: bs =>
|
||||
simp [zipWith_cons_cons, zipWithAux_toArray_succ', zipWithAux_toArray_zero, push_append_toArray]
|
||||
|
||||
@[simp] theorem zipWith_toArray (f : α → β → γ) (as : List α) (bs : List β) :
|
||||
Array.zipWith as.toArray bs.toArray f = (List.zipWith f as bs).toArray := by
|
||||
rw [Array.zipWith]
|
||||
simp [zipWithAux_toArray_zero]
|
||||
|
||||
@[simp] theorem zip_toArray (as : List α) (bs : List β) :
|
||||
Array.zip as.toArray bs.toArray = (List.zip as bs).toArray := by
|
||||
simp [Array.zip, zipWith_toArray, zip]
|
||||
|
||||
end List
|
||||
|
||||
namespace Array
|
||||
@@ -246,7 +392,7 @@ where
|
||||
aux (i r) :
|
||||
mapM.map f arr i r = (arr.toList.drop i).foldlM (fun bs a => bs.push <$> f a) r := by
|
||||
unfold mapM.map; split
|
||||
· rw [← List.get_drop_eq_drop _ i ‹_›]
|
||||
· rw [← List.getElem_cons_drop_succ_eq_drop ‹_›]
|
||||
simp only [aux (i + 1), map_eq_pure_bind, length_toList, List.foldlM_cons, bind_assoc,
|
||||
pure_bind]
|
||||
rfl
|
||||
@@ -1050,8 +1196,6 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
|
||||
|
||||
theorem size_empty : (#[] : Array α).size = 0 := rfl
|
||||
|
||||
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
|
||||
|
||||
/-! ### append -/
|
||||
|
||||
theorem push_eq_append_singleton (as : Array α) (x) : as.push x = as ++ #[x] := rfl
|
||||
@@ -1101,15 +1245,6 @@ theorem getElem?_append {as bs : Array α} {n : Nat} :
|
||||
· exact getElem?_append_left h
|
||||
· exact getElem?_append_right (by simpa using h)
|
||||
|
||||
@[simp] theorem append_nil (as : Array α) : as ++ #[] = as := by
|
||||
apply ext'; simp only [toList_append, toList_empty, List.append_nil]
|
||||
|
||||
@[simp] theorem nil_append (as : Array α) : #[] ++ as = as := by
|
||||
apply ext'; simp only [toList_append, toList_empty, List.nil_append]
|
||||
|
||||
@[simp] theorem append_assoc (as bs cs : Array α) : as ++ bs ++ cs = as ++ (bs ++ cs) := by
|
||||
apply ext'; simp only [toList_append, List.append_assoc]
|
||||
|
||||
/-! ### flatten -/
|
||||
|
||||
@[simp] theorem toList_flatten {l : Array (Array α)} :
|
||||
@@ -1460,6 +1595,54 @@ theorem swap_comm (a : Array α) {i j : Fin a.size} : a.swap i j = a.swap j i :=
|
||||
· split <;> simp_all
|
||||
· split <;> simp_all
|
||||
|
||||
/-! ### eraseIdx -/
|
||||
|
||||
theorem feraseIdx_eq_eraseIdx {a : Array α} {i : Fin a.size} :
|
||||
a.feraseIdx i = a.eraseIdx i.1 := by
|
||||
simp [eraseIdx]
|
||||
|
||||
/-! ### isPrefixOf -/
|
||||
|
||||
@[simp] theorem isPrefixOf_toList [BEq α] {as bs : Array α} :
|
||||
as.toList.isPrefixOf bs.toList = as.isPrefixOf bs := by
|
||||
cases as
|
||||
cases bs
|
||||
simp
|
||||
|
||||
/-! ### zipWith -/
|
||||
|
||||
@[simp] theorem toList_zipWith (f : α → β → γ) (as : Array α) (bs : Array β) :
|
||||
(Array.zipWith as bs f).toList = List.zipWith f as.toList bs.toList := by
|
||||
cases as
|
||||
cases bs
|
||||
simp
|
||||
|
||||
@[simp] theorem toList_zip (as : Array α) (bs : Array β) :
|
||||
(Array.zip as bs).toList = List.zip as.toList bs.toList := by
|
||||
simp [zip, toList_zipWith, List.zip]
|
||||
|
||||
/-! ### findSomeM?, findM?, findSome?, find? -/
|
||||
|
||||
@[simp] theorem findSomeM?_toList [Monad m] [LawfulMonad m] (p : α → m (Option β)) (as : Array α) :
|
||||
as.toList.findSomeM? p = as.findSomeM? p := by
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[simp] theorem findM?_toList [Monad m] [LawfulMonad m] (p : α → m Bool) (as : Array α) :
|
||||
as.toList.findM? p = as.findM? p := by
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[simp] theorem findSome?_toList (p : α → Option β) (as : Array α) :
|
||||
as.toList.findSome? p = as.findSome? p := by
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[simp] theorem find?_toList (p : α → Bool) (as : Array α) :
|
||||
as.toList.find? p = as.find? p := by
|
||||
cases as
|
||||
simp
|
||||
|
||||
end Array
|
||||
|
||||
open Array
|
||||
@@ -1475,11 +1658,6 @@ Our goal is to have `simp` "pull `List.toArray` outwards" as much as possible.
|
||||
@[simp] theorem toListRev_toArray (l : List α) : l.toArray.toListRev = l.reverse := by
|
||||
simp
|
||||
|
||||
@[simp] theorem push_append_toArray (as : Array α) (a : α) (l : List α) :
|
||||
as.push a ++ l.toArray = as ++ (a :: l).toArray := by
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp] theorem take_toArray (l : List α) (n : Nat) : l.toArray.take n = (l.take n).toArray := by
|
||||
apply ext'
|
||||
simp
|
||||
@@ -1611,7 +1789,7 @@ theorem filterMap_toArray (f : α → Option β) (l : List α) :
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp] theorem toArray_extract (l : List α) (start stop : Nat) :
|
||||
@[simp] theorem extract_toArray (l : List α) (start stop : Nat) :
|
||||
l.toArray.extract start stop = ((l.drop start).take (stop - start)).toArray := by
|
||||
apply ext'
|
||||
simp
|
||||
@@ -1619,6 +1797,64 @@ theorem filterMap_toArray (f : α → Option β) (l : List α) :
|
||||
@[simp] theorem toArray_ofFn (f : Fin n → α) : (ofFn f).toArray = Array.ofFn f := by
|
||||
ext <;> simp
|
||||
|
||||
theorem takeWhile_go_succ (p : α → Bool) (a : α) (l : List α) (i : Nat) :
|
||||
takeWhile.go p (a :: l).toArray (i+1) r = takeWhile.go p l.toArray i r := by
|
||||
rw [takeWhile.go, takeWhile.go]
|
||||
simp only [size_toArray, length_cons, Nat.add_lt_add_iff_right, Array.get_eq_getElem,
|
||||
getElem_toArray, getElem_cons_succ]
|
||||
split
|
||||
rw [takeWhile_go_succ]
|
||||
rfl
|
||||
|
||||
theorem takeWhile_go_toArray (p : α → Bool) (l : List α) (i : Nat) :
|
||||
Array.takeWhile.go p l.toArray i r = r ++ (takeWhile p (l.drop i)).toArray := by
|
||||
induction l generalizing i r with
|
||||
| nil => simp [takeWhile.go]
|
||||
| cons a l ih =>
|
||||
rw [takeWhile.go]
|
||||
cases i with
|
||||
| zero =>
|
||||
simp [takeWhile_go_succ, ih, takeWhile_cons]
|
||||
split <;> simp
|
||||
| succ i =>
|
||||
simp only [size_toArray, length_cons, Nat.add_lt_add_iff_right, Array.get_eq_getElem,
|
||||
getElem_toArray, getElem_cons_succ, drop_succ_cons]
|
||||
split <;> rename_i h₁
|
||||
· rw [takeWhile_go_succ, ih]
|
||||
rw [← getElem_cons_drop_succ_eq_drop h₁, takeWhile_cons]
|
||||
split <;> simp_all
|
||||
· simp_all [drop_eq_nil_of_le]
|
||||
|
||||
@[simp] theorem takeWhile_toArray (p : α → Bool) (l : List α) :
|
||||
l.toArray.takeWhile p = (l.takeWhile p).toArray := by
|
||||
simp [Array.takeWhile, takeWhile_go_toArray]
|
||||
|
||||
@[simp] theorem feraseIdx_toArray (l : List α) (i : Fin l.toArray.size) :
|
||||
l.toArray.feraseIdx i = (l.eraseIdx i).toArray := by
|
||||
rw [feraseIdx]
|
||||
split <;> rename_i h
|
||||
· rw [feraseIdx_toArray]
|
||||
simp only [swap_toArray, Fin.getElem_fin, toList_toArray, mk.injEq]
|
||||
rw [eraseIdx_set_gt (by simp), eraseIdx_set_eq]
|
||||
simp
|
||||
· rcases i with ⟨i, w⟩
|
||||
simp at h w
|
||||
have t : i = l.length - 1 := by omega
|
||||
simp [t]
|
||||
termination_by l.length - i
|
||||
decreasing_by
|
||||
rename_i h
|
||||
simp at h
|
||||
simp
|
||||
omega
|
||||
|
||||
@[simp] theorem eraseIdx_toArray (l : List α) (i : Nat) :
|
||||
l.toArray.eraseIdx i = (l.eraseIdx i).toArray := by
|
||||
rw [Array.eraseIdx]
|
||||
split
|
||||
· simp
|
||||
· simp_all [eraseIdx_eq_self.2]
|
||||
|
||||
end List
|
||||
|
||||
namespace Array
|
||||
@@ -1629,6 +1865,84 @@ namespace Array
|
||||
@[simp] theorem toList_ofFn (f : Fin n → α) : (Array.ofFn f).toList = List.ofFn f := by
|
||||
apply List.ext_getElem <;> simp
|
||||
|
||||
@[simp] theorem toList_takeWhile (p : α → Bool) (as : Array α) :
|
||||
(as.takeWhile p).toList = as.toList.takeWhile p := by
|
||||
induction as; simp
|
||||
|
||||
@[simp] theorem toList_feraseIdx (as : Array α) (i : Fin as.size) :
|
||||
(as.feraseIdx i).toList = as.toList.eraseIdx i.1 := by
|
||||
induction as
|
||||
simp
|
||||
|
||||
@[simp] theorem toList_eraseIdx (as : Array α) (i : Nat) :
|
||||
(as.eraseIdx i).toList = as.toList.eraseIdx i := by
|
||||
induction as
|
||||
simp
|
||||
|
||||
/-! ### findSomeRevM?, findRevM?, findSomeRev?, findRev? -/
|
||||
|
||||
@[simp] theorem findSomeRevM?_eq_findSomeM?_reverse
|
||||
[Monad m] [LawfulMonad m] (f : α → m (Option β)) (as : Array α) :
|
||||
as.findSomeRevM? f = as.reverse.findSomeM? f := by
|
||||
cases as
|
||||
rw [List.findSomeRevM?_toArray]
|
||||
simp
|
||||
|
||||
@[simp] theorem findRevM?_eq_findM?_reverse
|
||||
[Monad m] [LawfulMonad m] (f : α → m Bool) (as : Array α) :
|
||||
as.findRevM? f = as.reverse.findM? f := by
|
||||
cases as
|
||||
rw [List.findRevM?_toArray]
|
||||
simp
|
||||
|
||||
@[simp] theorem findSomeRev?_eq_findSome?_reverse (f : α → Option β) (as : Array α) :
|
||||
as.findSomeRev? f = as.reverse.findSome? f := by
|
||||
cases as
|
||||
simp [findSomeRev?, Id.run]
|
||||
|
||||
@[simp] theorem findRev?_eq_find?_reverse (f : α → Bool) (as : Array α) :
|
||||
as.findRev? f = as.reverse.find? f := by
|
||||
cases as
|
||||
simp [findRev?, Id.run]
|
||||
|
||||
/-! ### unzip -/
|
||||
|
||||
@[simp] theorem fst_unzip (as : Array (α × β)) : (Array.unzip as).fst = as.map Prod.fst := by
|
||||
simp only [unzip]
|
||||
rcases as with ⟨as⟩
|
||||
simp only [List.foldl_toArray']
|
||||
rw [← List.foldl_hom (f := Prod.fst) (g₂ := fun bs x => bs.push x.1) (H := by simp), ← List.foldl_map]
|
||||
simp
|
||||
|
||||
@[simp] theorem snd_unzip (as : Array (α × β)) : (Array.unzip as).snd = as.map Prod.snd := by
|
||||
simp only [unzip]
|
||||
rcases as with ⟨as⟩
|
||||
simp only [List.foldl_toArray']
|
||||
rw [← List.foldl_hom (f := Prod.snd) (g₂ := fun bs x => bs.push x.2) (H := by simp), ← List.foldl_map]
|
||||
simp
|
||||
|
||||
end Array
|
||||
|
||||
namespace List
|
||||
|
||||
@[simp] theorem unzip_toArray (as : List (α × β)) :
|
||||
as.toArray.unzip = Prod.map List.toArray List.toArray as.unzip := by
|
||||
ext1 <;> simp
|
||||
|
||||
end List
|
||||
|
||||
namespace Array
|
||||
|
||||
@[simp] theorem toList_fst_unzip (as : Array (α × β)) :
|
||||
as.unzip.1.toList = as.toList.unzip.1 := by
|
||||
cases as
|
||||
simp
|
||||
|
||||
@[simp] theorem toList_snd_unzip (as : Array (α × β)) :
|
||||
as.unzip.2.toList = as.toList.unzip.2 := by
|
||||
cases as
|
||||
simp
|
||||
|
||||
end Array
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
@@ -180,7 +180,7 @@ theorem carry_succ_one (i : Nat) (x : BitVec w) (h : 0 < w) :
|
||||
| zero => simp [carry_succ, h]
|
||||
| succ i ih =>
|
||||
rw [carry_succ, ih]
|
||||
simp only [getLsbD_one, add_one_ne_zero, decide_False, Bool.and_false, atLeastTwo_false_mid]
|
||||
simp only [getLsbD_one, add_one_ne_zero, decide_false, Bool.and_false, atLeastTwo_false_mid]
|
||||
cases hx : x.getLsbD (i+1)
|
||||
case false =>
|
||||
have : ∃ j ≤ i + 1, x.getLsbD j = false :=
|
||||
@@ -249,7 +249,7 @@ theorem getLsbD_add_add_bool {i : Nat} (i_lt : i < w) (x y : BitVec w) (c : Bool
|
||||
[ Nat.testBit_mod_two_pow,
|
||||
Nat.testBit_mul_two_pow_add_eq,
|
||||
i_lt,
|
||||
decide_True,
|
||||
decide_true,
|
||||
Bool.true_and,
|
||||
Nat.add_assoc,
|
||||
Nat.add_left_comm (_%_) (_ * _) _,
|
||||
@@ -392,7 +392,7 @@ theorem getLsbD_neg {i : Nat} {x : BitVec w} :
|
||||
by_cases hi : i < w
|
||||
· rw [getLsbD_add hi]
|
||||
have : 0 < w := by omega
|
||||
simp only [getLsbD_not, hi, decide_True, Bool.true_and, getLsbD_one, this, not_bne,
|
||||
simp only [getLsbD_not, hi, decide_true, Bool.true_and, getLsbD_one, this, not_bne,
|
||||
_root_.true_and, not_eq_eq_eq_not]
|
||||
cases i with
|
||||
| zero =>
|
||||
@@ -401,7 +401,7 @@ theorem getLsbD_neg {i : Nat} {x : BitVec w} :
|
||||
simp [hi, carry_zero]
|
||||
| succ =>
|
||||
rw [carry_succ_one _ _ (by omega), ← Bool.xor_not, ← decide_not]
|
||||
simp only [add_one_ne_zero, decide_False, getLsbD_not, and_eq_true, decide_eq_true_eq,
|
||||
simp only [add_one_ne_zero, decide_false, getLsbD_not, and_eq_true, decide_eq_true_eq,
|
||||
not_eq_eq_eq_not, Bool.not_true, false_bne, not_exists, _root_.not_and, not_eq_true,
|
||||
bne_left_inj, decide_eq_decide]
|
||||
constructor
|
||||
@@ -419,7 +419,7 @@ theorem getMsbD_neg {i : Nat} {x : BitVec w} :
|
||||
simp [hi]; omega
|
||||
case pos =>
|
||||
have h₁ : w - 1 - i < w := by omega
|
||||
simp only [hi, decide_True, h₁, Bool.true_and, Bool.bne_left_inj, decide_eq_decide]
|
||||
simp only [hi, decide_true, h₁, Bool.true_and, Bool.bne_left_inj, decide_eq_decide]
|
||||
constructor
|
||||
· rintro ⟨j, hj, h⟩
|
||||
refine ⟨w - 1 - j, by omega, by omega, by omega, _root_.cast ?_ h⟩
|
||||
@@ -455,7 +455,7 @@ theorem msb_neg {w : Nat} {x : BitVec w} :
|
||||
apply hmin
|
||||
apply eq_of_getMsbD_eq
|
||||
rintro ⟨i, hi⟩
|
||||
simp only [getMsbD_intMin, w_pos, decide_True, Bool.true_and]
|
||||
simp only [getMsbD_intMin, w_pos, decide_true, Bool.true_and]
|
||||
cases i
|
||||
case zero => exact hmsb
|
||||
case succ => exact getMsbD_x _ hi (by omega)
|
||||
@@ -476,7 +476,7 @@ theorem msb_abs {w : Nat} {x : BitVec w} :
|
||||
by_cases h₀ : 0 < w
|
||||
· by_cases h₁ : x = intMin w
|
||||
· simp [h₁, msb_intMin]
|
||||
· simp only [neg_eq, h₁, decide_False]
|
||||
· simp only [neg_eq, h₁, decide_false]
|
||||
by_cases h₂ : x.msb
|
||||
· simp [h₂, msb_neg]
|
||||
and_intros
|
||||
@@ -566,18 +566,18 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_add_twoPow (x : BitVec w) (i
|
||||
setWidth w (x.setWidth i) + (x &&& twoPow w i) := by
|
||||
rw [add_eq_or_of_and_eq_zero]
|
||||
· ext k
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp
|
||||
· simp only [getLsbD_twoPow, hik, decide_False, Bool.and_false, Bool.or_false]
|
||||
· simp only [getLsbD_twoPow, hik, decide_false, Bool.and_false, Bool.or_false]
|
||||
by_cases hik' : k < (i + 1)
|
||||
· have hik'' : k < i := by omega
|
||||
simp [hik', hik'']
|
||||
· have hik'' : ¬ (k < i) := by omega
|
||||
simp [hik', hik'']
|
||||
· ext k
|
||||
simp only [and_twoPow, getLsbD_and, getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and,
|
||||
simp only [and_twoPow, getLsbD_and, getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and,
|
||||
getLsbD_zero, and_eq_false_imp, and_eq_true, decide_eq_true_eq, and_imp]
|
||||
by_cases hi : x.getLsbD i <;> simp [hi] <;> omega
|
||||
|
||||
|
||||
@@ -123,7 +123,7 @@ theorem getMsbD_eq_getLsbD (x : BitVec w) (i : Nat) : x.getMsbD i = (decide (i <
|
||||
theorem getLsbD_eq_getMsbD (x : BitVec w) (i : Nat) : x.getLsbD i = (decide (i < w) && x.getMsbD (w - 1 - i)) := by
|
||||
rw [getMsbD]
|
||||
by_cases h₁ : i < w <;> by_cases h₂ : w - 1 - i < w <;>
|
||||
simp only [h₁, h₂] <;> simp only [decide_True, decide_False, Bool.false_and, Bool.and_false, Bool.true_and, Bool.and_true]
|
||||
simp only [h₁, h₂] <;> simp only [decide_true, decide_false, Bool.false_and, Bool.and_false, Bool.true_and, Bool.and_true]
|
||||
· congr
|
||||
omega
|
||||
all_goals
|
||||
@@ -386,7 +386,7 @@ theorem msb_eq_getLsbD_last (x : BitVec w) :
|
||||
· simp [Nat.div_eq_of_lt h, h]
|
||||
· simp only [h]
|
||||
rw [Nat.div_eq_sub_div (Nat.two_pow_pos w) h, Nat.div_eq_of_lt]
|
||||
· decide
|
||||
· simp
|
||||
· omega
|
||||
|
||||
@[bv_toNat] theorem getLsbD_succ_last (x : BitVec (w + 1)) :
|
||||
@@ -633,7 +633,7 @@ theorem getElem?_setWidth (m : Nat) (x : BitVec n) (i : Nat) :
|
||||
@[simp] theorem setWidth_setWidth_of_le (x : BitVec w) (h : k ≤ l) :
|
||||
(x.setWidth l).setWidth k = x.setWidth k := by
|
||||
ext i
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and]
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and]
|
||||
have p := lt_of_getLsbD (x := x) (i := i)
|
||||
revert p
|
||||
cases getLsbD x i <;> simp; omega
|
||||
@@ -663,7 +663,7 @@ theorem setWidth_one_eq_ofBool_getLsb_zero (x : BitVec w) :
|
||||
theorem setWidth_ofNat_one_eq_ofNat_one_of_lt {v w : Nat} (hv : 0 < v) :
|
||||
(BitVec.ofNat v 1).setWidth w = BitVec.ofNat w 1 := by
|
||||
ext ⟨i, hilt⟩
|
||||
simp only [getLsbD_setWidth, hilt, decide_True, getLsbD_ofNat, Bool.true_and,
|
||||
simp only [getLsbD_setWidth, hilt, decide_true, getLsbD_ofNat, Bool.true_and,
|
||||
Bool.and_iff_right_iff_imp, decide_eq_true_eq]
|
||||
intros hi₁
|
||||
have hv := Nat.testBit_one_eq_true_iff_self_eq_zero.mp hi₁
|
||||
@@ -735,9 +735,9 @@ theorem extractLsb'_eq_extractLsb {w : Nat} (x : BitVec w) (start len : Nat) (h
|
||||
|
||||
@[simp] theorem ofFin_add_rev (x : Fin (2^n)) : ofFin (x + x.rev) = allOnes n := by
|
||||
ext
|
||||
simp only [Fin.rev, getLsbD_ofFin, getLsbD_allOnes, Fin.is_lt, decide_True]
|
||||
simp only [Fin.rev, getLsbD_ofFin, getLsbD_allOnes, Fin.is_lt, decide_true]
|
||||
rw [Fin.add_def]
|
||||
simp only [Nat.testBit_mod_two_pow, Fin.is_lt, decide_True, Bool.true_and]
|
||||
simp only [Nat.testBit_mod_two_pow, Fin.is_lt, decide_true, Bool.true_and]
|
||||
have h : (x : Nat) + (2 ^ n - (x + 1)) = 2 ^ n - 1 := by omega
|
||||
rw [h, Nat.testBit_two_pow_sub_one]
|
||||
simp
|
||||
@@ -1089,21 +1089,21 @@ theorem zero_shiftLeft (n : Nat) : 0#w <<< n = 0#w := by
|
||||
theorem shiftLeft_xor_distrib (x y : BitVec w) (n : Nat) :
|
||||
(x ^^^ y) <<< n = (x <<< n) ^^^ (y <<< n) := by
|
||||
ext i
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_True, Bool.true_and, getLsbD_xor]
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, getLsbD_xor]
|
||||
by_cases h : i < n
|
||||
<;> simp [h]
|
||||
|
||||
theorem shiftLeft_and_distrib (x y : BitVec w) (n : Nat) :
|
||||
(x &&& y) <<< n = (x <<< n) &&& (y <<< n) := by
|
||||
ext i
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_True, Bool.true_and, getLsbD_and]
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, getLsbD_and]
|
||||
by_cases h : i < n
|
||||
<;> simp [h]
|
||||
|
||||
theorem shiftLeft_or_distrib (x y : BitVec w) (n : Nat) :
|
||||
(x ||| y) <<< n = (x <<< n) ||| (y <<< n) := by
|
||||
ext i
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_True, Bool.true_and, getLsbD_or]
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or]
|
||||
by_cases h : i < n
|
||||
<;> simp [h]
|
||||
|
||||
@@ -1114,9 +1114,9 @@ theorem shiftLeft_or_distrib (x y : BitVec w) (n : Nat) :
|
||||
· subst h; simp
|
||||
have t : w - 1 - k < w := by omega
|
||||
simp only [t]
|
||||
simp only [decide_True, Nat.sub_sub, Bool.true_and, Nat.add_assoc]
|
||||
simp only [decide_true, Nat.sub_sub, Bool.true_and, Nat.add_assoc]
|
||||
by_cases h₁ : k < w <;> by_cases h₂ : w - (1 + k) < i <;> by_cases h₃ : k + i < w
|
||||
<;> simp only [h₁, h₂, h₃, decide_False, h₂, decide_True, Bool.not_true, Bool.false_and, Bool.and_self,
|
||||
<;> simp only [h₁, h₂, h₃, decide_false, h₂, decide_true, Bool.not_true, Bool.false_and, Bool.and_self,
|
||||
Bool.true_and, Bool.false_eq, Bool.false_and, Bool.not_false]
|
||||
<;> (first | apply getLsbD_ge | apply Eq.symm; apply getLsbD_ge)
|
||||
<;> omega
|
||||
@@ -1160,7 +1160,7 @@ theorem shiftLeftZeroExtend_eq {x : BitVec w} :
|
||||
theorem shiftLeft_add {w : Nat} (x : BitVec w) (n m : Nat) :
|
||||
x <<< (n + m) = (x <<< n) <<< m := by
|
||||
ext i
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_True, Bool.true_and]
|
||||
simp only [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and]
|
||||
rw [show i - (n + m) = (i - m - n) by omega]
|
||||
cases h₂ : decide (i < m) <;>
|
||||
cases h₃ : decide (i - m < w) <;>
|
||||
@@ -1258,7 +1258,8 @@ theorem getMsbD_ushiftRight {x : BitVec w} {i n : Nat} :
|
||||
· simp [getLsbD_ge, show w ≤ (n + (w - 1 - i)) by omega]
|
||||
omega
|
||||
· by_cases h₁ : i < w
|
||||
· simp only [h, ushiftRight_eq, getLsbD_ushiftRight, show i - n < w by omega]
|
||||
· simp only [h, decide_false, Bool.not_false, show i - n < w by omega, decide_true,
|
||||
Bool.true_and]
|
||||
congr
|
||||
omega
|
||||
· simp [h, h₁]
|
||||
@@ -1327,17 +1328,17 @@ theorem getLsbD_sshiftRight (x : BitVec w) (s i : Nat) :
|
||||
rcases hmsb : x.msb with rfl | rfl
|
||||
· simp only [sshiftRight_eq_of_msb_false hmsb, getLsbD_ushiftRight, Bool.if_false_right]
|
||||
by_cases hi : i ≥ w
|
||||
· simp only [hi, decide_True, Bool.not_true, Bool.false_and]
|
||||
· simp only [hi, decide_true, Bool.not_true, Bool.false_and]
|
||||
apply getLsbD_ge
|
||||
omega
|
||||
· simp only [hi, decide_False, Bool.not_false, Bool.true_and, Bool.iff_and_self,
|
||||
· simp only [hi, decide_false, Bool.not_false, Bool.true_and, Bool.iff_and_self,
|
||||
decide_eq_true_eq]
|
||||
intros hlsb
|
||||
apply BitVec.lt_of_getLsbD hlsb
|
||||
· by_cases hi : i ≥ w
|
||||
· simp [hi]
|
||||
· simp only [sshiftRight_eq_of_msb_true hmsb, getLsbD_not, getLsbD_ushiftRight, Bool.not_and,
|
||||
Bool.not_not, hi, decide_False, Bool.not_false, Bool.if_true_right, Bool.true_and,
|
||||
Bool.not_not, hi, decide_false, Bool.not_false, Bool.if_true_right, Bool.true_and,
|
||||
Bool.and_iff_right_iff_imp, Bool.or_eq_true, Bool.not_eq_true', decide_eq_false_iff_not,
|
||||
Nat.not_lt, decide_eq_true_eq]
|
||||
omega
|
||||
@@ -1382,7 +1383,7 @@ theorem msb_sshiftRight {n : Nat} {x : BitVec w} :
|
||||
rw [msb_eq_getLsbD_last, getLsbD_sshiftRight, msb_eq_getLsbD_last]
|
||||
by_cases hw₀ : w = 0
|
||||
· simp [hw₀]
|
||||
· simp only [show ¬(w ≤ w - 1) by omega, decide_False, Bool.not_false, Bool.true_and,
|
||||
· simp only [show ¬(w ≤ w - 1) by omega, decide_false, Bool.not_false, Bool.true_and,
|
||||
ite_eq_right_iff]
|
||||
intros h
|
||||
simp [show n = 0 by omega]
|
||||
@@ -1401,7 +1402,7 @@ theorem sshiftRight_add {x : BitVec w} {m n : Nat} :
|
||||
simp only [getLsbD_sshiftRight, Nat.add_assoc]
|
||||
by_cases h₁ : w ≤ (i : Nat)
|
||||
· simp [h₁]
|
||||
· simp only [h₁, decide_False, Bool.not_false, Bool.true_and]
|
||||
· simp only [h₁, decide_false, Bool.not_false, Bool.true_and]
|
||||
by_cases h₂ : n + ↑i < w
|
||||
· simp [h₂]
|
||||
· simp only [h₂, ↓reduceIte]
|
||||
@@ -1413,7 +1414,7 @@ theorem sshiftRight_add {x : BitVec w} {m n : Nat} :
|
||||
theorem not_sshiftRight {b : BitVec w} :
|
||||
~~~b.sshiftRight n = (~~~b).sshiftRight n := by
|
||||
ext i
|
||||
simp only [getLsbD_not, Fin.is_lt, decide_True, getLsbD_sshiftRight, Bool.not_and, Bool.not_not,
|
||||
simp only [getLsbD_not, Fin.is_lt, decide_true, getLsbD_sshiftRight, Bool.not_and, Bool.not_not,
|
||||
Bool.true_and, msb_not]
|
||||
by_cases h : w ≤ i
|
||||
<;> by_cases h' : n + i < w
|
||||
@@ -1431,15 +1432,15 @@ theorem getMsbD_sshiftRight {x : BitVec w} {i n : Nat} :
|
||||
getMsbD (x.sshiftRight n) i = (decide (i < w) && if i < n then x.msb else getMsbD x (i - n)) := by
|
||||
simp only [getMsbD, BitVec.getLsbD_sshiftRight]
|
||||
by_cases h : i < w
|
||||
· simp only [h, decide_True, Bool.true_and]
|
||||
· simp only [h, decide_true, Bool.true_and]
|
||||
by_cases h₁ : w ≤ w - 1 - i
|
||||
· simp [h₁]
|
||||
omega
|
||||
· simp only [h₁, decide_False, Bool.not_false, Bool.true_and]
|
||||
· simp only [h₁, decide_false, Bool.not_false, Bool.true_and]
|
||||
by_cases h₂ : i < n
|
||||
· simp only [h₂, ↓reduceIte, ite_eq_right_iff]
|
||||
omega
|
||||
· simp only [show i - n < w by omega, h₂, ↓reduceIte, decide_True, Bool.true_and]
|
||||
· simp only [show i - n < w by omega, h₂, ↓reduceIte, decide_true, Bool.true_and]
|
||||
by_cases h₄ : n + (w - 1 - i) < w <;> (simp only [h₄, ↓reduceIte]; congr; omega)
|
||||
· simp [h]
|
||||
|
||||
@@ -1459,15 +1460,15 @@ theorem getMsbD_sshiftRight' {x y: BitVec w} {i : Nat} :
|
||||
(x.sshiftRight y.toNat).getMsbD i = (decide (i < w) && if i < y.toNat then x.msb else x.getMsbD (i - y.toNat)) := by
|
||||
simp only [BitVec.sshiftRight', getMsbD, BitVec.getLsbD_sshiftRight]
|
||||
by_cases h : i < w
|
||||
· simp only [h, decide_True, Bool.true_and]
|
||||
· simp only [h, decide_true, Bool.true_and]
|
||||
by_cases h₁ : w ≤ w - 1 - i
|
||||
· simp [h₁]
|
||||
omega
|
||||
· simp only [h₁, decide_False, Bool.not_false, Bool.true_and]
|
||||
· simp only [h₁, decide_false, Bool.not_false, Bool.true_and]
|
||||
by_cases h₂ : i < y.toNat
|
||||
· simp only [h₂, ↓reduceIte, ite_eq_right_iff]
|
||||
omega
|
||||
· simp only [show i - y.toNat < w by omega, h₂, ↓reduceIte, decide_True, Bool.true_and]
|
||||
· simp only [show i - y.toNat < w by omega, h₂, ↓reduceIte, decide_true, Bool.true_and]
|
||||
by_cases h₄ : y.toNat + (w - 1 - i) < w <;> (simp only [h₄, ↓reduceIte]; congr; omega)
|
||||
· simp [h]
|
||||
|
||||
@@ -1492,11 +1493,11 @@ theorem signExtend_eq_not_setWidth_not_of_msb_false {x : BitVec w} {v : Nat} (hm
|
||||
x.signExtend v = x.setWidth v := by
|
||||
ext i
|
||||
by_cases hv : i < v
|
||||
· simp only [signExtend, getLsbD, getLsbD_setWidth, hv, decide_True, Bool.true_and, toNat_ofInt,
|
||||
· simp only [signExtend, getLsbD, getLsbD_setWidth, hv, decide_true, Bool.true_and, toNat_ofInt,
|
||||
BitVec.toInt_eq_msb_cond, hmsb, ↓reduceIte, reduceCtorEq]
|
||||
rw [Int.ofNat_mod_ofNat, Int.toNat_ofNat, Nat.testBit_mod_two_pow]
|
||||
simp [BitVec.testBit_toNat]
|
||||
· simp only [getLsbD_setWidth, hv, decide_False, Bool.false_and]
|
||||
· simp only [getLsbD_setWidth, hv, decide_false, Bool.false_and]
|
||||
apply getLsbD_ge
|
||||
omega
|
||||
|
||||
@@ -1538,7 +1539,7 @@ theorem getElem_signExtend {x : BitVec w} {v i : Nat} (h : i < v) :
|
||||
theorem signExtend_eq_setWidth_of_lt (x : BitVec w) {v : Nat} (hv : v ≤ w):
|
||||
x.signExtend v = x.setWidth v := by
|
||||
ext i
|
||||
simp only [getLsbD_signExtend, Fin.is_lt, decide_True, Bool.true_and, getLsbD_setWidth,
|
||||
simp only [getLsbD_signExtend, Fin.is_lt, decide_true, Bool.true_and, getLsbD_setWidth,
|
||||
ite_eq_left_iff, Nat.not_lt]
|
||||
omega
|
||||
|
||||
@@ -1622,7 +1623,7 @@ theorem setWidth_append {x : BitVec w} {y : BitVec v} :
|
||||
(x ++ y).setWidth k = if h : k ≤ v then y.setWidth k else (x.setWidth (k - v) ++ y).cast (by omega) := by
|
||||
apply eq_of_getLsbD_eq
|
||||
intro i
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, getLsbD_append, Bool.true_and]
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, getLsbD_append, Bool.true_and]
|
||||
split
|
||||
· have t : i < v := by omega
|
||||
simp [t]
|
||||
@@ -1634,7 +1635,7 @@ theorem setWidth_append {x : BitVec w} {y : BitVec v} :
|
||||
@[simp] theorem setWidth_append_of_eq {x : BitVec v} {y : BitVec w} (h : w' = w) : setWidth (v' + w') (x ++ y) = setWidth v' x ++ setWidth w' y := by
|
||||
subst h
|
||||
ext i
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, getLsbD_append, cond_eq_if,
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, getLsbD_append, cond_eq_if,
|
||||
decide_eq_true_eq, Bool.true_and, setWidth_eq]
|
||||
split
|
||||
· simp_all
|
||||
@@ -1705,13 +1706,13 @@ theorem shiftRight_shiftRight {w : Nat} (x : BitVec w) (n m : Nat) :
|
||||
|
||||
theorem getLsbD_rev (x : BitVec w) (i : Fin w) :
|
||||
x.getLsbD i.rev = x.getMsbD i := by
|
||||
simp only [getLsbD, Fin.val_rev, getMsbD, Fin.is_lt, decide_True, Bool.true_and]
|
||||
simp only [getLsbD, Fin.val_rev, getMsbD, Fin.is_lt, decide_true, Bool.true_and]
|
||||
congr 1
|
||||
omega
|
||||
|
||||
theorem getElem_rev {x : BitVec w} {i : Fin w}:
|
||||
x[i.rev] = x.getMsbD i := by
|
||||
simp only [Fin.getElem_fin, Fin.val_rev, getMsbD, Fin.is_lt, decide_True, Bool.true_and]
|
||||
simp only [Fin.getElem_fin, Fin.val_rev, getMsbD, Fin.is_lt, decide_true, Bool.true_and]
|
||||
congr 1
|
||||
omega
|
||||
|
||||
@@ -1741,7 +1742,7 @@ theorem getLsbD_cons (b : Bool) {n} (x : BitVec n) (i : Nat) :
|
||||
· have p1 : ¬(n ≤ i) := by omega
|
||||
have p2 : i ≠ n := by omega
|
||||
simp [p1, p2]
|
||||
· simp only [i_eq_n, ge_iff_le, Nat.le_refl, decide_True, Nat.sub_self, Nat.testBit_zero,
|
||||
· simp only [i_eq_n, ge_iff_le, Nat.le_refl, decide_true, Nat.sub_self, Nat.testBit_zero,
|
||||
Bool.true_and, testBit_toNat, getLsbD_ge, Bool.or_false, ↓reduceIte]
|
||||
cases b <;> trivial
|
||||
· have p1 : i ≠ n := by omega
|
||||
@@ -1756,7 +1757,7 @@ theorem getElem_cons {b : Bool} {n} {x : BitVec n} {i : Nat} (h : i < n + 1) :
|
||||
· have p1 : ¬(n ≤ i) := by omega
|
||||
have p2 : i ≠ n := by omega
|
||||
simp [p1, p2]
|
||||
· simp only [i_eq_n, ge_iff_le, Nat.le_refl, decide_True, Nat.sub_self, Nat.testBit_zero,
|
||||
· simp only [i_eq_n, ge_iff_le, Nat.le_refl, decide_true, Nat.sub_self, Nat.testBit_zero,
|
||||
Bool.true_and, testBit_toNat, getLsbD_ge, Bool.or_false, ↓reduceIte]
|
||||
cases b <;> trivial
|
||||
· have p1 : i ≠ n := by omega
|
||||
@@ -1776,7 +1777,7 @@ theorem setWidth_succ (x : BitVec w) :
|
||||
setWidth (i+1) x = cons (getLsbD x i) (setWidth i x) := by
|
||||
apply eq_of_getLsbD_eq
|
||||
intro j
|
||||
simp only [getLsbD_setWidth, getLsbD_cons, j.isLt, decide_True, Bool.true_and]
|
||||
simp only [getLsbD_setWidth, getLsbD_cons, j.isLt, decide_true, Bool.true_and]
|
||||
if j_eq : j.val = i then
|
||||
simp [j_eq]
|
||||
else
|
||||
@@ -1884,7 +1885,7 @@ theorem getLsbD_shiftConcat_eq_decide (x : BitVec w) (b : Bool) (i : Nat) :
|
||||
theorem shiftRight_sub_one_eq_shiftConcat (n : BitVec w) (hwn : 0 < wn) :
|
||||
n >>> (wn - 1) = (n >>> wn).shiftConcat (n.getLsbD (wn - 1)) := by
|
||||
ext i
|
||||
simp only [getLsbD_ushiftRight, getLsbD_shiftConcat, Fin.is_lt, decide_True, Bool.true_and]
|
||||
simp only [getLsbD_ushiftRight, getLsbD_shiftConcat, Fin.is_lt, decide_true, Bool.true_and]
|
||||
split
|
||||
· simp [*]
|
||||
· congr 1; omega
|
||||
@@ -1925,7 +1926,7 @@ theorem getMsbD_concat {i w : Nat} {b : Bool} {x : BitVec w} :
|
||||
· simp [h₀]
|
||||
· by_cases h₁ : i < w
|
||||
· simp [h₀, h₁, show ¬ w - i = 0 by omega, show i < w + 1 by omega, Nat.sub_sub, Nat.add_comm]
|
||||
· simp only [show w - i = 0 by omega, ↓reduceIte, h₁, h₀, decide_False, Bool.false_and,
|
||||
· simp only [show w - i = 0 by omega, ↓reduceIte, h₁, h₀, decide_false, Bool.false_and,
|
||||
Bool.and_eq_false_imp, decide_eq_true_eq]
|
||||
intro
|
||||
omega
|
||||
@@ -1933,10 +1934,10 @@ theorem getMsbD_concat {i w : Nat} {b : Bool} {x : BitVec w} :
|
||||
@[simp]
|
||||
theorem msb_concat {w : Nat} {b : Bool} {x : BitVec w} :
|
||||
(x.concat b).msb = if 0 < w then x.msb else b := by
|
||||
simp only [BitVec.msb, getMsbD_eq_getLsbD, Nat.zero_lt_succ, decide_True, Nat.add_one_sub_one,
|
||||
simp only [BitVec.msb, getMsbD_eq_getLsbD, Nat.zero_lt_succ, decide_true, Nat.add_one_sub_one,
|
||||
Nat.sub_zero, Bool.true_and]
|
||||
by_cases h₀ : 0 < w
|
||||
· simp only [Nat.lt_add_one, getLsbD_eq_getElem, getElem_concat, h₀, ↓reduceIte, decide_True,
|
||||
· simp only [Nat.lt_add_one, getLsbD_eq_getElem, getElem_concat, h₀, ↓reduceIte, decide_true,
|
||||
Bool.true_and, ite_eq_right_iff]
|
||||
intro
|
||||
omega
|
||||
@@ -2026,9 +2027,9 @@ theorem sub_def {n} (x y : BitVec n) : x - y = .ofNat n ((2^n - y.toNat) + x.toN
|
||||
|
||||
@[simp] theorem toFin_sub (x y : BitVec n) : (x - y).toFin = toFin x - toFin y := rfl
|
||||
|
||||
@[simp] theorem ofFin_sub (x : Fin (2^n)) (y : BitVec n) : .ofFin x - y = .ofFin (x - y.toFin) :=
|
||||
theorem ofFin_sub (x : Fin (2^n)) (y : BitVec n) : .ofFin x - y = .ofFin (x - y.toFin) :=
|
||||
rfl
|
||||
@[simp] theorem sub_ofFin (x : BitVec n) (y : Fin (2^n)) : x - .ofFin y = .ofFin (x.toFin - y) :=
|
||||
theorem sub_ofFin (x : BitVec n) (y : Fin (2^n)) : x - .ofFin y = .ofFin (x.toFin - y) :=
|
||||
rfl
|
||||
|
||||
-- Remark: we don't use `[simp]` here because simproc` subsumes it for literals.
|
||||
@@ -2506,7 +2507,7 @@ theorem smod_zero {x : BitVec n} : x.smod 0#n = x := by
|
||||
@[simp] theorem getElem_ofBoolListBE (h : i < bs.length) :
|
||||
(ofBoolListBE bs)[i] = bs[bs.length - 1 - i] := by
|
||||
rw [← getLsbD_eq_getElem, getLsbD_ofBoolListBE]
|
||||
simp only [h, decide_True, List.getD_eq_getElem?_getD, Bool.true_and]
|
||||
simp only [h, decide_true, List.getD_eq_getElem?_getD, Bool.true_and]
|
||||
rw [List.getElem?_eq_getElem (by omega)]
|
||||
simp
|
||||
|
||||
@@ -2694,6 +2695,9 @@ theorem getElem_rotateRight {x : BitVec w} {r i : Nat} (h : i < w) :
|
||||
|
||||
/- ## twoPow -/
|
||||
|
||||
theorem twoPow_eq (w : Nat) (i : Nat) : twoPow w i = 1#w <<< i := by
|
||||
dsimp [twoPow]
|
||||
|
||||
@[simp, bv_toNat]
|
||||
theorem toNat_twoPow (w : Nat) (i : Nat) : (twoPow w i).toNat = 2^i % 2^w := by
|
||||
rcases w with rfl | w
|
||||
@@ -2708,7 +2712,7 @@ theorem getLsbD_twoPow (i j : Nat) : (twoPow w i).getLsbD j = ((i < w) && (i = j
|
||||
· simp
|
||||
· simp only [twoPow, getLsbD_shiftLeft, getLsbD_ofNat]
|
||||
by_cases hj : j < i
|
||||
· simp only [hj, decide_True, Bool.not_true, Bool.and_false, Bool.false_and, Bool.false_eq,
|
||||
· simp only [hj, decide_true, Bool.not_true, Bool.and_false, Bool.false_and, Bool.false_eq,
|
||||
Bool.and_eq_false_imp, decide_eq_true_eq, decide_eq_false_iff_not]
|
||||
omega
|
||||
· by_cases hi : Nat.testBit 1 (j - i)
|
||||
@@ -2771,7 +2775,7 @@ theorem twoPow_zero {w : Nat} : twoPow w 0 = 1#w := by
|
||||
theorem shiftLeft_eq_mul_twoPow (x : BitVec w) (n : Nat) :
|
||||
x <<< n = x * (BitVec.twoPow w n) := by
|
||||
ext i
|
||||
simp [getLsbD_shiftLeft, Fin.is_lt, decide_True, Bool.true_and, mul_twoPow_eq_shiftLeft]
|
||||
simp [getLsbD_shiftLeft, Fin.is_lt, decide_true, Bool.true_and, mul_twoPow_eq_shiftLeft]
|
||||
|
||||
/- ### cons -/
|
||||
|
||||
@@ -2799,7 +2803,7 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_of_getLsbD_false
|
||||
setWidth w (x.setWidth (i + 1)) =
|
||||
setWidth w (x.setWidth i) := by
|
||||
ext k
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp [hx]
|
||||
@@ -2815,7 +2819,7 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_or_twoPow_of_getLsbD_true
|
||||
setWidth w (x.setWidth (i + 1)) =
|
||||
setWidth w (x.setWidth i) ||| (twoPow w i) := by
|
||||
ext k
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_True, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
simp only [getLsbD_setWidth, Fin.is_lt, decide_true, Bool.true_and, getLsbD_or, getLsbD_and]
|
||||
by_cases hik : i = k
|
||||
· subst hik
|
||||
simp [hx]
|
||||
@@ -2825,7 +2829,7 @@ theorem setWidth_setWidth_succ_eq_setWidth_setWidth_or_twoPow_of_getLsbD_true
|
||||
theorem and_one_eq_setWidth_ofBool_getLsbD {x : BitVec w} :
|
||||
(x &&& 1#w) = setWidth w (ofBool (x.getLsbD 0)) := by
|
||||
ext i
|
||||
simp only [getLsbD_and, getLsbD_one, getLsbD_setWidth, Fin.is_lt, decide_True, getLsbD_ofBool,
|
||||
simp only [getLsbD_and, getLsbD_one, getLsbD_setWidth, Fin.is_lt, decide_true, getLsbD_ofBool,
|
||||
Bool.true_and]
|
||||
by_cases h : ((i : Nat) = 0) <;> simp [h] <;> omega
|
||||
|
||||
@@ -2862,13 +2866,13 @@ theorem getLsbD_replicate {n w : Nat} (x : BitVec w) :
|
||||
case succ n ih =>
|
||||
simp only [replicate_succ_eq, getLsbD_cast, getLsbD_append]
|
||||
by_cases hi : i < w * (n + 1)
|
||||
· simp only [hi, decide_True, Bool.true_and]
|
||||
· simp only [hi, decide_true, Bool.true_and]
|
||||
by_cases hi' : i < w * n
|
||||
· simp [hi', ih]
|
||||
· simp only [hi', decide_False, cond_false]
|
||||
· simp only [hi', decide_false, cond_false]
|
||||
rw [Nat.sub_mul_eq_mod_of_lt_of_le] <;> omega
|
||||
· rw [Nat.mul_succ] at hi ⊢
|
||||
simp only [show ¬i < w * n by omega, decide_False, cond_false, hi, Bool.false_and]
|
||||
simp only [show ¬i < w * n by omega, decide_false, cond_false, hi, Bool.false_and]
|
||||
apply BitVec.getLsbD_ge (x := x) (i := i - w * n) (ge := by omega)
|
||||
|
||||
@[simp]
|
||||
@@ -2929,7 +2933,7 @@ theorem toInt_intMin_le (x : BitVec w) :
|
||||
apply Int.le_bmod (by omega)
|
||||
|
||||
theorem intMin_sle (x : BitVec w) : (intMin w).sle x := by
|
||||
simp only [BitVec.sle, toInt_intMin_le x, decide_True]
|
||||
simp only [BitVec.sle, toInt_intMin_le x, decide_true]
|
||||
|
||||
@[simp]
|
||||
theorem neg_intMin {w : Nat} : -intMin w = intMin w := by
|
||||
|
||||
@@ -169,6 +169,13 @@ theorem pmap_ne_nil_iff {P : α → Prop} (f : (a : α) → P a → β) {xs : Li
|
||||
(H : ∀ (a : α), a ∈ xs → P a) : xs.pmap f H ≠ [] ↔ xs ≠ [] := by
|
||||
simp
|
||||
|
||||
theorem pmap_eq_self {l : List α} {p : α → Prop} (hp : ∀ (a : α), a ∈ l → p a)
|
||||
(f : (a : α) → p a → α) : l.pmap f hp = l ↔ ∀ a (h : a ∈ l), f a (hp a h) = a := by
|
||||
rw [pmap_eq_map_attach]
|
||||
conv => lhs; rhs; rw [← attach_map_subtype_val l]
|
||||
rw [map_inj_left]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem attach_eq_nil_iff {l : List α} : l.attach = [] ↔ l = [] :=
|
||||
pmap_eq_nil_iff
|
||||
|
||||
@@ -38,7 +38,7 @@ The operations are organized as follow:
|
||||
* Sublists: `take`, `drop`, `takeWhile`, `dropWhile`, `partition`, `dropLast`,
|
||||
`isPrefixOf`, `isPrefixOf?`, `isSuffixOf`, `isSuffixOf?`, `Subset`, `Sublist`,
|
||||
`rotateLeft` and `rotateRight`.
|
||||
* Manipulating elements: `replace`, `insert`, `modify`, `erase`, `eraseP`, `eraseIdx`.
|
||||
* Manipulating elements: `replace`, `modify`, `insert`, `insertIdx`, `erase`, `eraseP`, `eraseIdx`.
|
||||
* Finding elements: `find?`, `findSome?`, `findIdx`, `indexOf`, `findIdx?`, `indexOf?`,
|
||||
`countP`, `count`, and `lookup`.
|
||||
* Logic: `any`, `all`, `or`, and `and`.
|
||||
@@ -1113,12 +1113,6 @@ theorem replace_cons [BEq α] {a : α} :
|
||||
(a::as).replace b c = match b == a with | true => c::as | false => a :: replace as b c :=
|
||||
rfl
|
||||
|
||||
/-! ### insert -/
|
||||
|
||||
/-- Inserts an element into a list without duplication. -/
|
||||
@[inline] protected def insert [BEq α] (a : α) (l : List α) : List α :=
|
||||
if l.elem a then l else a :: l
|
||||
|
||||
/-! ### modify -/
|
||||
|
||||
/--
|
||||
@@ -1148,6 +1142,21 @@ Apply `f` to the nth element of the list, if it exists, replacing that element w
|
||||
def modify (f : α → α) : Nat → List α → List α :=
|
||||
modifyTailIdx (modifyHead f)
|
||||
|
||||
/-! ### insert -/
|
||||
|
||||
/-- Inserts an element into a list without duplication. -/
|
||||
@[inline] protected def insert [BEq α] (a : α) (l : List α) : List α :=
|
||||
if l.elem a then l else a :: l
|
||||
|
||||
/--
|
||||
`insertIdx n a l` inserts `a` into the list `l` after the first `n` elements of `l`
|
||||
```
|
||||
insertIdx 2 1 [1, 2, 3, 4] = [1, 2, 1, 3, 4]
|
||||
```
|
||||
-/
|
||||
def insertIdx (n : Nat) (a : α) : List α → List α :=
|
||||
modifyTailIdx (cons a) n
|
||||
|
||||
/-! ### erase -/
|
||||
|
||||
/--
|
||||
|
||||
@@ -5,6 +5,8 @@ Author: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Init.Control.Basic
|
||||
import Init.Control.Id
|
||||
import Init.Control.Lawful
|
||||
import Init.Data.List.Basic
|
||||
|
||||
namespace List
|
||||
@@ -207,6 +209,16 @@ def findM? {m : Type → Type u} [Monad m] {α : Type} (p : α → m Bool) : Lis
|
||||
| true => pure (some a)
|
||||
| false => findM? p as
|
||||
|
||||
@[simp]
|
||||
theorem findM?_id (p : α → Bool) (as : List α) : findM? (m := Id) p as = as.find? p := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
simp only [findM?, find?]
|
||||
cases p a with
|
||||
| true => rfl
|
||||
| false => rw [ih]; rfl
|
||||
|
||||
@[specialize]
|
||||
def findSomeM? {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f : α → m (Option β)) : List α → m (Option β)
|
||||
| [] => pure none
|
||||
@@ -215,6 +227,28 @@ def findSomeM? {m : Type u → Type v} [Monad m] {α : Type w} {β : Type u} (f
|
||||
| some b => pure (some b)
|
||||
| none => findSomeM? f as
|
||||
|
||||
@[simp]
|
||||
theorem findSomeM?_id (f : α → Option β) (as : List α) : findSomeM? (m := Id) f as = as.findSome? f := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
simp only [findSomeM?, findSome?]
|
||||
cases f a with
|
||||
| some b => rfl
|
||||
| none => rw [ih]; rfl
|
||||
|
||||
theorem findM?_eq_findSomeM? [Monad m] [LawfulMonad m] (p : α → m Bool) (as : List α) :
|
||||
as.findM? p = as.findSomeM? fun a => return if (← p a) then some a else none := by
|
||||
induction as with
|
||||
| nil => rfl
|
||||
| cons a as ih =>
|
||||
simp only [findM?, findSomeM?]
|
||||
simp [ih]
|
||||
congr
|
||||
apply funext
|
||||
intro b
|
||||
cases b <;> simp
|
||||
|
||||
@[inline] protected def forIn' {α : Type u} {β : Type v} {m : Type v → Type w} [Monad m] (as : List α) (init : β) (f : (a : α) → a ∈ as → β → m (ForInStep β)) : m β :=
|
||||
let rec @[specialize] loop : (as' : List α) → (b : β) → Exists (fun bs => bs ++ as' = as) → m β
|
||||
| [], b, _ => pure b
|
||||
|
||||
@@ -206,7 +206,8 @@ theorem IsInfix.findSome?_eq_none {l₁ l₂ : List α} {f : α → Option β} (
|
||||
@[simp] theorem find?_eq_none : find? p l = none ↔ ∀ x ∈ l, ¬ p x := by
|
||||
induction l <;> simp [find?_cons]; split <;> simp [*]
|
||||
|
||||
theorem find?_eq_some : xs.find? p = some b ↔ p b ∧ ∃ as bs, xs = as ++ b :: bs ∧ ∀ a ∈ as, !p a := by
|
||||
theorem find?_eq_some_iff_append :
|
||||
xs.find? p = some b ↔ p b ∧ ∃ as bs, xs = as ++ b :: bs ∧ ∀ a ∈ as, !p a := by
|
||||
induction xs with
|
||||
| nil => simp
|
||||
| cons x xs ih =>
|
||||
@@ -242,6 +243,9 @@ theorem find?_eq_some : xs.find? p = some b ↔ p b ∧ ∃ as bs, xs = as ++ b
|
||||
cases h₁
|
||||
simp
|
||||
|
||||
@[deprecated find?_eq_some_iff_append (since := "2024-11-06")]
|
||||
abbrev find?_eq_some := @find?_eq_some_iff_append
|
||||
|
||||
@[simp]
|
||||
theorem find?_cons_eq_some : (a :: xs).find? p = some b ↔ (p a ∧ a = b) ∨ (!p a ∧ xs.find? p = some b) := by
|
||||
rw [find?_cons]
|
||||
@@ -347,7 +351,7 @@ theorem find?_flatten_eq_some {xs : List (List α)} {p : α → Bool} {a : α} :
|
||||
xs.flatten.find? p = some a ↔
|
||||
p a ∧ ∃ as ys zs bs, xs = as ++ (ys ++ a :: zs) :: bs ∧
|
||||
(∀ a ∈ as, ∀ x ∈ a, !p x) ∧ (∀ x ∈ ys, !p x) := by
|
||||
rw [find?_eq_some]
|
||||
rw [find?_eq_some_iff_append]
|
||||
constructor
|
||||
· rintro ⟨h, ⟨ys, zs, h₁, h₂⟩⟩
|
||||
refine ⟨h, ?_⟩
|
||||
|
||||
@@ -38,7 +38,7 @@ The following operations were already given `@[csimp]` replacements in `Init/Dat
|
||||
|
||||
The following operations are given `@[csimp]` replacements below:
|
||||
`set`, `filterMap`, `foldr`, `append`, `bind`, `join`,
|
||||
`take`, `takeWhile`, `dropLast`, `replace`, `modify`, `erase`, `eraseIdx`, `zipWith`,
|
||||
`take`, `takeWhile`, `dropLast`, `replace`, `modify`, `insertIdx`, `erase`, `eraseIdx`, `zipWith`,
|
||||
`enumFrom`, and `intercalate`.
|
||||
|
||||
-/
|
||||
@@ -215,6 +215,23 @@ theorem modifyTR_go_eq : ∀ l n, modifyTR.go f l n acc = acc.toList ++ modify f
|
||||
@[csimp] theorem modify_eq_modifyTR : @modify = @modifyTR := by
|
||||
funext α f n l; simp [modifyTR, modifyTR_go_eq]
|
||||
|
||||
/-! ### insertIdx -/
|
||||
|
||||
/-- Tail-recursive version of `insertIdx`. -/
|
||||
@[inline] def insertIdxTR (n : Nat) (a : α) (l : List α) : List α := go n l #[] where
|
||||
/-- Auxiliary for `insertIdxTR`: `insertIdxTR.go a n l acc = acc.toList ++ insertIdx n a l`. -/
|
||||
go : Nat → List α → Array α → List α
|
||||
| 0, l, acc => acc.toListAppend (a :: l)
|
||||
| _, [], acc => acc.toList
|
||||
| n+1, a :: l, acc => go n l (acc.push a)
|
||||
|
||||
theorem insertIdxTR_go_eq : ∀ n l, insertIdxTR.go a n l acc = acc.toList ++ insertIdx n a l
|
||||
| 0, l | _+1, [] => by simp [insertIdxTR.go, insertIdx]
|
||||
| n+1, a :: l => by simp [insertIdxTR.go, insertIdx, insertIdxTR_go_eq n l]
|
||||
|
||||
@[csimp] theorem insertIdx_eq_insertIdxTR : @insertIdx = @insertIdxTR := by
|
||||
funext α f n l; simp [insertIdxTR, insertIdxTR_go_eq]
|
||||
|
||||
/-! ### erase -/
|
||||
|
||||
/-- Tail recursive version of `List.erase`. -/
|
||||
|
||||
@@ -863,14 +863,14 @@ theorem foldr_map (f : α₁ → α₂) (g : α₂ → β → β) (l : List α
|
||||
(l.map f).foldr g init = l.foldr (fun x y => g (f x) y) init := by
|
||||
induction l generalizing init <;> simp [*]
|
||||
|
||||
theorem foldl_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
theorem foldl_map' (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
|
||||
(l.map g).foldl f' (g a) = g (l.foldl f a) := by
|
||||
induction l generalizing a
|
||||
· simp
|
||||
· simp [*, h]
|
||||
|
||||
theorem foldr_map' {α β : Type u} (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
theorem foldr_map' (g : α → β) (f : α → α → α) (f' : β → β → β) (a : α) (l : List α)
|
||||
(h : ∀ x y, f' (g x) (g y) = g (f x y)) :
|
||||
(l.map g).foldr f' (g a) = g (l.foldr f a) := by
|
||||
induction l generalizing a
|
||||
@@ -2700,6 +2700,12 @@ theorem flatMap_reverse {β} (l : List α) (f : α → List β) : (l.reverse.fla
|
||||
l.reverse.foldr f b = l.foldl (fun x y => f y x) b :=
|
||||
(foldl_reverse ..).symm.trans <| by simp
|
||||
|
||||
theorem foldl_eq_foldr_reverse (l : List α) (f : β → α → β) (b) :
|
||||
l.foldl f b = l.reverse.foldr (fun x y => f y x) b := by simp
|
||||
|
||||
theorem foldr_eq_foldl_reverse (l : List α) (f : α → β → β) (b) :
|
||||
l.foldr f b = l.reverse.foldl (fun x y => f y x) b := by simp
|
||||
|
||||
@[simp] theorem reverse_replicate (n) (a : α) : reverse (replicate n a) = replicate n a :=
|
||||
eq_replicate_iff.2
|
||||
⟨by rw [length_reverse, length_replicate],
|
||||
|
||||
@@ -14,3 +14,4 @@ import Init.Data.List.Nat.Erase
|
||||
import Init.Data.List.Nat.Find
|
||||
import Init.Data.List.Nat.BEq
|
||||
import Init.Data.List.Nat.Modify
|
||||
import Init.Data.List.Nat.InsertIdx
|
||||
|
||||
@@ -64,3 +64,82 @@ theorem getElem_eraseIdx_of_ge (l : List α) (i : Nat) (j : Nat) (h : j < (l.era
|
||||
(l.eraseIdx i)[j] = l[j + 1]'(by rw [length_eraseIdx] at h; split at h <;> omega) := by
|
||||
rw [getElem_eraseIdx, dif_neg]
|
||||
omega
|
||||
|
||||
theorem eraseIdx_set_eq {l : List α} {i : Nat} {a : α} :
|
||||
(l.set i a).eraseIdx i = l.eraseIdx i := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro n h₁ h₂
|
||||
rw [getElem_eraseIdx, getElem_eraseIdx]
|
||||
split <;>
|
||||
· rw [getElem_set_ne]
|
||||
omega
|
||||
|
||||
theorem eraseIdx_set_lt {l : List α} {i : Nat} {j : Nat} {a : α} (h : j < i) :
|
||||
(l.set i a).eraseIdx j = (l.eraseIdx j).set (i - 1) a := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro n h₁ h₂
|
||||
simp only [length_eraseIdx, length_set] at h₁
|
||||
simp only [getElem_eraseIdx, getElem_set]
|
||||
split
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· omega
|
||||
· split
|
||||
· omega
|
||||
· rfl
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· omega
|
||||
· have t : i - 1 ≠ n := by omega
|
||||
simp [t]
|
||||
|
||||
theorem eraseIdx_set_gt {l : List α} {i : Nat} {j : Nat} {a : α} (h : i < j) :
|
||||
(l.set i a).eraseIdx j = (l.eraseIdx j).set i a := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
· intro n h₁ h₂
|
||||
simp only [length_eraseIdx, length_set] at h₁
|
||||
simp only [getElem_eraseIdx, getElem_set]
|
||||
split
|
||||
· rfl
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· omega
|
||||
· have t : i ≠ n := by omega
|
||||
simp [t]
|
||||
|
||||
@[simp] theorem set_getElem_succ_eraseIdx_succ
|
||||
{l : List α} {i : Nat} (h : i + 1 < l.length) :
|
||||
(l.eraseIdx (i + 1)).set i l[i + 1] = l.eraseIdx i := by
|
||||
apply ext_getElem
|
||||
· simp only [length_set, length_eraseIdx, h, ↓reduceIte]
|
||||
rw [if_pos]
|
||||
omega
|
||||
· intro n h₁ h₂
|
||||
simp [getElem_set, getElem_eraseIdx]
|
||||
split
|
||||
· split
|
||||
· omega
|
||||
· simp_all
|
||||
· split
|
||||
· split
|
||||
· rfl
|
||||
· omega
|
||||
· have t : ¬ n < i := by omega
|
||||
simp [t]
|
||||
|
||||
@[simp] theorem eraseIdx_length_sub_one (l : List α) :
|
||||
(l.eraseIdx (l.length - 1)) = l.dropLast := by
|
||||
apply ext_getElem
|
||||
· simp [length_eraseIdx]
|
||||
omega
|
||||
· intro n h₁ h₂
|
||||
rw [getElem_eraseIdx_of_lt, getElem_dropLast]
|
||||
simp_all
|
||||
|
||||
end List
|
||||
|
||||
@@ -9,6 +9,32 @@ import Init.Data.List.Find
|
||||
|
||||
namespace List
|
||||
|
||||
open Nat
|
||||
|
||||
theorem find?_eq_some_iff_getElem {xs : List α} {p : α → Bool} {b : α} :
|
||||
xs.find? p = some b ↔ p b ∧ ∃ i h, xs[i] = b ∧ ∀ j : Nat, (hj : j < i) → !p xs[j] := by
|
||||
rw [find?_eq_some_iff_append]
|
||||
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, and_congr_right_iff]
|
||||
intro w
|
||||
constructor
|
||||
· rintro ⟨as, ⟨bs, rfl⟩, h⟩
|
||||
refine ⟨as.length, ⟨?_, ?_, ?_⟩⟩
|
||||
· simp only [length_append, length_cons]
|
||||
refine Nat.lt_add_of_pos_right (zero_lt_succ bs.length)
|
||||
· rw [getElem_append_right (Nat.le_refl as.length)]
|
||||
simp
|
||||
· intro j h'
|
||||
rw [getElem_append_left h']
|
||||
exact h _ (getElem_mem h')
|
||||
· rintro ⟨i, h, rfl, h'⟩
|
||||
refine ⟨xs.take i, ⟨xs.drop (i+1), ?_⟩, ?_⟩
|
||||
· rw [getElem_cons_drop, take_append_drop]
|
||||
· intro a m
|
||||
rw [mem_take_iff_getElem] at m
|
||||
obtain ⟨j, h, rfl⟩ := m
|
||||
apply h'
|
||||
omega
|
||||
|
||||
theorem findIdx?_eq_some_le_of_findIdx?_eq_some {xs : List α} {p q : α → Bool} (w : ∀ x ∈ xs, p x → q x) {i : Nat}
|
||||
(h : xs.findIdx? p = some i) : ∃ j, j ≤ i ∧ xs.findIdx? q = some j := by
|
||||
simp only [findIdx?_eq_findSome?_enum] at h
|
||||
|
||||
242
src/Init/Data/List/Nat/InsertIdx.lean
Normal file
242
src/Init/Data/List/Nat/InsertIdx.lean
Normal file
@@ -0,0 +1,242 @@
|
||||
/-
|
||||
Copyright (c) 2014 Parikshit Khanna. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.List.Nat.Modify
|
||||
|
||||
/-!
|
||||
# insertIdx
|
||||
|
||||
Proves various lemmas about `List.insertIdx`.
|
||||
-/
|
||||
|
||||
open Function
|
||||
|
||||
open Nat
|
||||
|
||||
namespace List
|
||||
|
||||
universe u
|
||||
|
||||
variable {α : Type u}
|
||||
|
||||
section InsertIdx
|
||||
|
||||
variable {a : α}
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_zero (s : List α) (x : α) : insertIdx 0 x s = x :: s :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_succ_nil (n : Nat) (a : α) : insertIdx (n + 1) a [] = [] :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_succ_cons (s : List α) (hd x : α) (n : Nat) :
|
||||
insertIdx (n + 1) x (hd :: s) = hd :: insertIdx n x s :=
|
||||
rfl
|
||||
|
||||
theorem length_insertIdx : ∀ n as, (insertIdx n a as).length = if n ≤ as.length then as.length + 1 else as.length
|
||||
| 0, _ => by simp
|
||||
| n + 1, [] => by simp
|
||||
| n + 1, a :: as => by
|
||||
simp only [insertIdx_succ_cons, length_cons, length_insertIdx, Nat.add_le_add_iff_right]
|
||||
split <;> rfl
|
||||
|
||||
theorem length_insertIdx_of_le_length (h : n ≤ length as) : length (insertIdx n a as) = length as + 1 := by
|
||||
simp [length_insertIdx, h]
|
||||
|
||||
theorem length_insertIdx_of_length_lt (h : length as < n) : length (insertIdx n a as) = length as := by
|
||||
simp [length_insertIdx, h]
|
||||
|
||||
theorem eraseIdx_insertIdx (n : Nat) (l : List α) : (l.insertIdx n a).eraseIdx n = l := by
|
||||
rw [eraseIdx_eq_modifyTailIdx, insertIdx, modifyTailIdx_modifyTailIdx_eq]
|
||||
exact modifyTailIdx_id _ _
|
||||
|
||||
theorem insertIdx_eraseIdx_of_ge :
|
||||
∀ n m as,
|
||||
n < length as → n ≤ m → insertIdx m a (as.eraseIdx n) = (as.insertIdx (m + 1) a).eraseIdx n
|
||||
| 0, 0, [], has, _ => (Nat.lt_irrefl _ has).elim
|
||||
| 0, 0, _ :: as, _, _ => by simp [eraseIdx, insertIdx]
|
||||
| 0, _ + 1, _ :: _, _, _ => rfl
|
||||
| n + 1, m + 1, a :: as, has, hmn =>
|
||||
congrArg (cons a) <|
|
||||
insertIdx_eraseIdx_of_ge n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn)
|
||||
|
||||
theorem insertIdx_eraseIdx_of_le :
|
||||
∀ n m as,
|
||||
n < length as → m ≤ n → insertIdx m a (as.eraseIdx n) = (as.insertIdx m a).eraseIdx (n + 1)
|
||||
| _, 0, _ :: _, _, _ => rfl
|
||||
| n + 1, m + 1, a :: as, has, hmn =>
|
||||
congrArg (cons a) <|
|
||||
insertIdx_eraseIdx_of_le n m as (Nat.lt_of_succ_lt_succ has) (Nat.le_of_succ_le_succ hmn)
|
||||
|
||||
theorem insertIdx_comm (a b : α) :
|
||||
∀ (i j : Nat) (l : List α) (_ : i ≤ j) (_ : j ≤ length l),
|
||||
(l.insertIdx i a).insertIdx (j + 1) b = (l.insertIdx j b).insertIdx i a
|
||||
| 0, j, l => by simp [insertIdx]
|
||||
| _ + 1, 0, _ => fun h => (Nat.not_lt_zero _ h).elim
|
||||
| i + 1, j + 1, [] => by simp
|
||||
| i + 1, j + 1, c :: l => fun h₀ h₁ => by
|
||||
simp only [insertIdx_succ_cons, cons.injEq, true_and]
|
||||
exact insertIdx_comm a b i j l (Nat.le_of_succ_le_succ h₀) (Nat.le_of_succ_le_succ h₁)
|
||||
|
||||
theorem mem_insertIdx {a b : α} :
|
||||
∀ {n : Nat} {l : List α} (_ : n ≤ l.length), a ∈ l.insertIdx n b ↔ a = b ∨ a ∈ l
|
||||
| 0, as, _ => by simp
|
||||
| _ + 1, [], h => (Nat.not_succ_le_zero _ h).elim
|
||||
| n + 1, a' :: as, h => by
|
||||
rw [List.insertIdx_succ_cons, mem_cons, mem_insertIdx (Nat.le_of_succ_le_succ h),
|
||||
← or_assoc, @or_comm (a = a'), or_assoc, mem_cons]
|
||||
|
||||
theorem insertIdx_of_length_lt (l : List α) (x : α) (n : Nat) (h : l.length < n) :
|
||||
insertIdx n x l = l := by
|
||||
induction l generalizing n with
|
||||
| nil =>
|
||||
cases n
|
||||
· simp at h
|
||||
· simp
|
||||
| cons x l ih =>
|
||||
cases n
|
||||
· simp at h
|
||||
· simp only [Nat.succ_lt_succ_iff, length] at h
|
||||
simpa using ih _ h
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_length_self (l : List α) (x : α) : insertIdx l.length x l = l ++ [x] := by
|
||||
induction l with
|
||||
| nil => simp
|
||||
| cons x l ih => simpa using ih
|
||||
|
||||
theorem length_le_length_insertIdx (l : List α) (x : α) (n : Nat) :
|
||||
l.length ≤ (insertIdx n x l).length := by
|
||||
simp only [length_insertIdx]
|
||||
split <;> simp
|
||||
|
||||
theorem length_insertIdx_le_succ (l : List α) (x : α) (n : Nat) :
|
||||
(insertIdx n x l).length ≤ l.length + 1 := by
|
||||
simp only [length_insertIdx]
|
||||
split <;> simp
|
||||
|
||||
theorem getElem_insertIdx_of_lt {l : List α} {x : α} {n k : Nat} (hn : k < n)
|
||||
(hk : k < (insertIdx n x l).length) :
|
||||
(insertIdx n x l)[k] = l[k]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
|
||||
induction n generalizing k l with
|
||||
| zero => simp at hn
|
||||
| succ n ih =>
|
||||
cases l with
|
||||
| nil => simp
|
||||
| cons _ _=>
|
||||
cases k
|
||||
· simp [get]
|
||||
· rw [Nat.succ_lt_succ_iff] at hn
|
||||
simpa using ih hn _
|
||||
|
||||
@[simp]
|
||||
theorem getElem_insertIdx_self {l : List α} {x : α} {n : Nat} (hn : n < (insertIdx n x l).length) :
|
||||
(insertIdx n x l)[n] = x := by
|
||||
induction l generalizing n with
|
||||
| nil =>
|
||||
simp [length_insertIdx] at hn
|
||||
split at hn
|
||||
· simp_all
|
||||
· omega
|
||||
| cons _ _ ih =>
|
||||
cases n
|
||||
· simp
|
||||
· simp only [insertIdx_succ_cons, length_cons, length_insertIdx, Nat.add_lt_add_iff_right] at hn ih
|
||||
simpa using ih hn
|
||||
|
||||
theorem getElem_insertIdx_of_ge {l : List α} {x : α} {n k : Nat} (hn : n + 1 ≤ k)
|
||||
(hk : k < (insertIdx n x l).length) :
|
||||
(insertIdx n x l)[k] = l[k - 1]'(by simp [length_insertIdx] at hk; split at hk <;> omega) := by
|
||||
induction l generalizing n k with
|
||||
| nil =>
|
||||
cases n with
|
||||
| zero =>
|
||||
simp only [insertIdx_zero, length_singleton, lt_one_iff] at hk
|
||||
omega
|
||||
| succ n => simp at hk
|
||||
| cons _ _ ih =>
|
||||
cases n with
|
||||
| zero =>
|
||||
simp only [insertIdx_zero] at hk
|
||||
cases k with
|
||||
| zero => omega
|
||||
| succ k => simp
|
||||
| succ n =>
|
||||
cases k with
|
||||
| zero => simp
|
||||
| succ k =>
|
||||
simp only [insertIdx_succ_cons, getElem_cons_succ]
|
||||
rw [ih (by omega)]
|
||||
cases k with
|
||||
| zero => omega
|
||||
| succ k => simp
|
||||
|
||||
theorem getElem_insertIdx {l : List α} {x : α} {n k : Nat} (h : k < (insertIdx n x l).length) :
|
||||
(insertIdx n x l)[k] =
|
||||
if h₁ : k < n then
|
||||
l[k]'(by simp [length_insertIdx] at h; split at h <;> omega)
|
||||
else
|
||||
if h₂ : k = n then
|
||||
x
|
||||
else
|
||||
l[k-1]'(by simp [length_insertIdx] at h; split at h <;> omega) := by
|
||||
split <;> rename_i h₁
|
||||
· rw [getElem_insertIdx_of_lt h₁]
|
||||
· split <;> rename_i h₂
|
||||
· subst h₂
|
||||
rw [getElem_insertIdx_self h]
|
||||
· rw [getElem_insertIdx_of_ge (by omega)]
|
||||
|
||||
theorem getElem?_insertIdx {l : List α} {x : α} {n k : Nat} :
|
||||
(insertIdx n x l)[k]? =
|
||||
if k < n then
|
||||
l[k]?
|
||||
else
|
||||
if k = n then
|
||||
if k ≤ l.length then some x else none
|
||||
else
|
||||
l[k-1]? := by
|
||||
rw [getElem?_def]
|
||||
split <;> rename_i h
|
||||
· rw [getElem_insertIdx h]
|
||||
simp only [length_insertIdx] at h
|
||||
split <;> rename_i h₁
|
||||
· rw [getElem?_def, dif_pos]
|
||||
· split <;> rename_i h₂
|
||||
· rw [if_pos]
|
||||
split at h <;> omega
|
||||
· rw [getElem?_def]
|
||||
simp only [Option.some_eq_dite_none_right, exists_prop, and_true]
|
||||
split at h <;> omega
|
||||
· simp only [length_insertIdx] at h
|
||||
split <;> rename_i h₁
|
||||
· rw [getElem?_eq_none]
|
||||
split at h <;> omega
|
||||
· split <;> rename_i h₂
|
||||
· rw [if_neg]
|
||||
split at h <;> omega
|
||||
· rw [getElem?_eq_none]
|
||||
split at h <;> omega
|
||||
|
||||
theorem getElem?_insertIdx_of_lt {l : List α} {x : α} {n k : Nat} (h : k < n) :
|
||||
(insertIdx n x l)[k]? = l[k]? := by
|
||||
rw [getElem?_insertIdx, if_pos h]
|
||||
|
||||
theorem getElem?_insertIdx_self {l : List α} {x : α} {n : Nat} :
|
||||
(insertIdx n x l)[n]? = if n ≤ l.length then some x else none := by
|
||||
rw [getElem?_insertIdx, if_neg (by omega)]
|
||||
simp
|
||||
|
||||
theorem getElem?_insertIdx_of_ge {l : List α} {x : α} {n k : Nat} (h : n + 1 ≤ k) :
|
||||
(insertIdx n x l)[k]? = l[k - 1]? := by
|
||||
rw [getElem?_insertIdx, if_neg (by omega), if_neg (by omega)]
|
||||
|
||||
end InsertIdx
|
||||
|
||||
end List
|
||||
@@ -110,6 +110,25 @@ theorem exists_of_modifyTailIdx (f : List α → List α) {n} {l : List α} (h :
|
||||
⟨_, _, (take_append_drop n l).symm, length_take_of_le h⟩
|
||||
⟨_, _, eq, hl, hl ▸ eq ▸ modifyTailIdx_add (n := 0) ..⟩
|
||||
|
||||
theorem modifyTailIdx_modifyTailIdx {f g : List α → List α} (m : Nat) :
|
||||
∀ (n) (l : List α),
|
||||
(l.modifyTailIdx f n).modifyTailIdx g (m + n) =
|
||||
l.modifyTailIdx (fun l => (f l).modifyTailIdx g m) n
|
||||
| 0, _ => rfl
|
||||
| _ + 1, [] => rfl
|
||||
| n + 1, a :: l => congrArg (List.cons a) (modifyTailIdx_modifyTailIdx m n l)
|
||||
|
||||
theorem modifyTailIdx_modifyTailIdx_le {f g : List α → List α} (m n : Nat) (l : List α)
|
||||
(h : n ≤ m) :
|
||||
(l.modifyTailIdx f n).modifyTailIdx g m =
|
||||
l.modifyTailIdx (fun l => (f l).modifyTailIdx g (m - n)) n := by
|
||||
rcases Nat.exists_eq_add_of_le h with ⟨m, rfl⟩
|
||||
rw [Nat.add_comm, modifyTailIdx_modifyTailIdx, Nat.add_sub_cancel]
|
||||
|
||||
theorem modifyTailIdx_modifyTailIdx_eq {f g : List α → List α} (n : Nat) (l : List α) :
|
||||
(l.modifyTailIdx f n).modifyTailIdx g n = l.modifyTailIdx (g ∘ f) n := by
|
||||
rw [modifyTailIdx_modifyTailIdx_le n n l (Nat.le_refl n), Nat.sub_self]; rfl
|
||||
|
||||
/-! ### modify -/
|
||||
|
||||
@[simp] theorem modify_nil (f : α → α) (n) : [].modify f n = [] := by cases n <;> rfl
|
||||
|
||||
@@ -108,7 +108,7 @@ theorem range'_eq_append_iff : range' s n = xs ++ ys ↔ ∃ k, k ≤ n ∧ xs =
|
||||
|
||||
@[simp] theorem find?_range'_eq_some {s n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(range' s n).find? p = some i ↔ p i ∧ i ∈ range' s n ∧ ∀ j, s ≤ j → j < i → !p j := by
|
||||
rw [find?_eq_some]
|
||||
rw [find?_eq_some_iff_append]
|
||||
simp only [Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, mem_range'_1,
|
||||
and_congr_right_iff]
|
||||
simp only [range'_eq_append_iff, eq_comm (a := i :: _), range'_eq_cons_iff]
|
||||
@@ -282,7 +282,7 @@ theorem find?_iota_eq_none {n : Nat} {p : Nat → Bool} :
|
||||
|
||||
@[simp] theorem find?_iota_eq_some {n : Nat} {i : Nat} {p : Nat → Bool} :
|
||||
(iota n).find? p = some i ↔ p i ∧ i ∈ iota n ∧ ∀ j, i < j → j ≤ n → !p j := by
|
||||
rw [find?_eq_some]
|
||||
rw [find?_eq_some_iff_append]
|
||||
simp only [iota_eq_reverse_range', reverse_eq_append_iff, reverse_cons, append_assoc, cons_append,
|
||||
nil_append, Bool.not_eq_eq_eq_not, Bool.not_true, exists_and_right, mem_reverse, mem_range'_1,
|
||||
and_congr_right_iff]
|
||||
|
||||
@@ -52,4 +52,29 @@ protected theorem getElem?_ofFn (f : Fin n → α) (i) : (ofFn f)[i]? = if h : i
|
||||
rw [dif_neg] <;>
|
||||
simpa using h
|
||||
|
||||
/-- `ofFn` on an empty domain is the empty list. -/
|
||||
@[simp]
|
||||
theorem ofFn_zero (f : Fin 0 → α) : ofFn f = [] :=
|
||||
ext_get (by simp) (fun i hi₁ hi₂ => by contradiction)
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_succ {n} (f : Fin (n + 1) → α) : ofFn f = f 0 :: ofFn fun i => f i.succ :=
|
||||
ext_get (by simp) (fun i hi₁ hi₂ => by
|
||||
cases i
|
||||
· simp
|
||||
· simp)
|
||||
|
||||
@[simp]
|
||||
theorem ofFn_eq_nil_iff {f : Fin n → α} : ofFn f = [] ↔ n = 0 := by
|
||||
cases n <;> simp only [ofFn_zero, ofFn_succ, eq_self_iff_true, Nat.succ_ne_zero, reduceCtorEq]
|
||||
|
||||
theorem head_ofFn {n} (f : Fin n → α) (h : ofFn f ≠ []) :
|
||||
(ofFn f).head h = f ⟨0, Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)⟩ := by
|
||||
rw [← getElem_zero (length_ofFn _ ▸ Nat.pos_of_ne_zero (mt ofFn_eq_nil_iff.2 h)),
|
||||
List.getElem_ofFn]
|
||||
|
||||
theorem getLast_ofFn {n} (f : Fin n → α) (h : ofFn f ≠ []) :
|
||||
(ofFn f).getLast h = f ⟨n - 1, Nat.sub_one_lt (mt ofFn_eq_nil_iff.2 h)⟩ := by
|
||||
simp [getLast_eq_getElem, length_ofFn, List.getElem_ofFn]
|
||||
|
||||
end List
|
||||
|
||||
@@ -190,7 +190,7 @@ theorem set_drop {l : List α} {n m : Nat} {a : α} :
|
||||
theorem take_concat_get (l : List α) (i : Nat) (h : i < l.length) :
|
||||
(l.take i).concat l[i] = l.take (i+1) :=
|
||||
Eq.symm <| (append_left_inj _).1 <| (take_append_drop (i+1) l).trans <| by
|
||||
rw [concat_eq_append, append_assoc, singleton_append, get_drop_eq_drop, take_append_drop]
|
||||
rw [concat_eq_append, append_assoc, singleton_append, getElem_cons_drop_succ_eq_drop, take_append_drop]
|
||||
|
||||
@[deprecated take_succ_cons (since := "2024-07-25")]
|
||||
theorem take_cons_succ : (a::as).take (i+1) = a :: as.take i := rfl
|
||||
|
||||
@@ -357,7 +357,7 @@ theorem testBit_two_pow_of_ne {n m : Nat} (hm : n ≠ m) : testBit (2 ^ n) m = f
|
||||
| zero => simp
|
||||
| succ n =>
|
||||
rw [mod_eq_of_lt (a := 1) (Nat.one_lt_two_pow (by omega)), mod_two_eq_one_iff_testBit_zero, testBit_two_pow_sub_one ]
|
||||
simp only [zero_lt_succ, decide_True]
|
||||
simp only [zero_lt_succ, decide_true]
|
||||
|
||||
@[simp] theorem mod_two_pos_mod_two_eq_one : x % 2 ^ j % 2 = 1 ↔ (0 < j) ∧ x % 2 = 1 := by
|
||||
rw [mod_two_eq_one_iff_testBit_zero, testBit_mod_two_pow]
|
||||
|
||||
@@ -374,9 +374,15 @@ end choice
|
||||
|
||||
-- See `Init.Data.Option.List` for lemmas about `toList`.
|
||||
|
||||
@[simp] theorem or_some : (some a).or o = some a := rfl
|
||||
@[simp] theorem some_or : (some a).or o = some a := rfl
|
||||
@[simp] theorem none_or : none.or o = o := rfl
|
||||
|
||||
@[deprecated some_or (since := "2024-11-03")] theorem or_some : (some a).or o = some a := rfl
|
||||
|
||||
/-- This will be renamed to `or_some` once the existing deprecated lemma is removed. -/
|
||||
@[simp] theorem or_some' {o : Option α} : o.or (some a) = o.getD a := by
|
||||
cases o <;> rfl
|
||||
|
||||
theorem or_eq_bif : or o o' = bif o.isSome then o else o' := by
|
||||
cases o <;> rfl
|
||||
|
||||
|
||||
@@ -22,6 +22,48 @@ structure Int8 where
|
||||
-/
|
||||
toUInt8 : UInt8
|
||||
|
||||
/--
|
||||
The type of signed 16-bit integers. This type has special support in the
|
||||
compiler to make it actually 16 bits rather than wrapping a `Nat`.
|
||||
-/
|
||||
structure Int16 where
|
||||
/--
|
||||
Obtain the `UInt16` that is 2's complement equivalent to the `Int16`.
|
||||
-/
|
||||
toUInt16 : UInt16
|
||||
|
||||
/--
|
||||
The type of signed 32-bit integers. This type has special support in the
|
||||
compiler to make it actually 32 bits rather than wrapping a `Nat`.
|
||||
-/
|
||||
structure Int32 where
|
||||
/--
|
||||
Obtain the `UInt32` that is 2's complement equivalent to the `Int32`.
|
||||
-/
|
||||
toUInt32 : UInt32
|
||||
|
||||
/--
|
||||
The type of signed 64-bit integers. This type has special support in the
|
||||
compiler to make it actually 64 bits rather than wrapping a `Nat`.
|
||||
-/
|
||||
structure Int64 where
|
||||
/--
|
||||
Obtain the `UInt64` that is 2's complement equivalent to the `Int64`.
|
||||
-/
|
||||
toUInt64 : UInt64
|
||||
|
||||
/--
|
||||
A `ISize` is a signed integer with the size of a word for the platform's architecture.
|
||||
|
||||
For example, if running on a 32-bit machine, ISize is equivalent to `Int32`.
|
||||
Or on a 64-bit machine, `Int64`.
|
||||
-/
|
||||
structure ISize where
|
||||
/--
|
||||
Obtain the `USize` that is 2's complement equivalent to the `ISize`.
|
||||
-/
|
||||
toUSize : USize
|
||||
|
||||
/-- The size of type `Int8`, that is, `2^8 = 256`. -/
|
||||
abbrev Int8.size : Nat := 256
|
||||
|
||||
@@ -32,12 +74,16 @@ Obtain the `BitVec` that contains the 2's complement representation of the `Int8
|
||||
|
||||
@[extern "lean_int8_of_int"]
|
||||
def Int8.ofInt (i : @& Int) : Int8 := ⟨⟨BitVec.ofInt 8 i⟩⟩
|
||||
@[extern "lean_int8_of_int"]
|
||||
@[extern "lean_int8_of_nat"]
|
||||
def Int8.ofNat (n : @& Nat) : Int8 := ⟨⟨BitVec.ofNat 8 n⟩⟩
|
||||
abbrev Int.toInt8 := Int8.ofInt
|
||||
abbrev Nat.toInt8 := Int8.ofNat
|
||||
@[extern "lean_int8_to_int"]
|
||||
def Int8.toInt (i : Int8) : Int := i.toBitVec.toInt
|
||||
/--
|
||||
This function has the same behavior as `Int.toNat` for negative numbers.
|
||||
If you want to obtain the 2's complement representation use `toBitVec`.
|
||||
-/
|
||||
@[inline] def Int8.toNat (i : Int8) : Nat := i.toInt.toNat
|
||||
@[extern "lean_int8_neg"]
|
||||
def Int8.neg (i : Int8) : Int8 := ⟨⟨-i.toBitVec⟩⟩
|
||||
@@ -58,7 +104,7 @@ def Int8.mul (a b : Int8) : Int8 := ⟨⟨a.toBitVec * b.toBitVec⟩⟩
|
||||
@[extern "lean_int8_div"]
|
||||
def Int8.div (a b : Int8) : Int8 := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int8_mod"]
|
||||
def Int8.mod (a b : Int8) : Int8 := ⟨⟨BitVec.smod a.toBitVec b.toBitVec⟩⟩
|
||||
def Int8.mod (a b : Int8) : Int8 := ⟨⟨BitVec.srem a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int8_land"]
|
||||
def Int8.land (a b : Int8) : Int8 := ⟨⟨a.toBitVec &&& b.toBitVec⟩⟩
|
||||
@[extern "lean_int8_lor"]
|
||||
@@ -66,9 +112,9 @@ def Int8.lor (a b : Int8) : Int8 := ⟨⟨a.toBitVec ||| b.toBitVec⟩⟩
|
||||
@[extern "lean_int8_xor"]
|
||||
def Int8.xor (a b : Int8) : Int8 := ⟨⟨a.toBitVec ^^^ b.toBitVec⟩⟩
|
||||
@[extern "lean_int8_shift_left"]
|
||||
def Int8.shiftLeft (a b : Int8) : Int8 := ⟨⟨a.toBitVec <<< (mod b 8).toBitVec⟩⟩
|
||||
def Int8.shiftLeft (a b : Int8) : Int8 := ⟨⟨a.toBitVec <<< (b.toBitVec.smod 8)⟩⟩
|
||||
@[extern "lean_int8_shift_right"]
|
||||
def Int8.shiftRight (a b : Int8) : Int8 := ⟨⟨BitVec.sshiftRight' a.toBitVec (mod b 8).toBitVec⟩⟩
|
||||
def Int8.shiftRight (a b : Int8) : Int8 := ⟨⟨BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 8)⟩⟩
|
||||
@[extern "lean_int8_complement"]
|
||||
def Int8.complement (a : Int8) : Int8 := ⟨⟨~~~a.toBitVec⟩⟩
|
||||
|
||||
@@ -114,3 +160,429 @@ instance (a b : Int8) : Decidable (a < b) := Int8.decLt a b
|
||||
instance (a b : Int8) : Decidable (a ≤ b) := Int8.decLe a b
|
||||
instance : Max Int8 := maxOfLe
|
||||
instance : Min Int8 := minOfLe
|
||||
|
||||
/-- The size of type `Int16`, that is, `2^16 = 65536`. -/
|
||||
abbrev Int16.size : Nat := 65536
|
||||
|
||||
/--
|
||||
Obtain the `BitVec` that contains the 2's complement representation of the `Int16`.
|
||||
-/
|
||||
@[inline] def Int16.toBitVec (x : Int16) : BitVec 16 := x.toUInt16.toBitVec
|
||||
|
||||
@[extern "lean_int16_of_int"]
|
||||
def Int16.ofInt (i : @& Int) : Int16 := ⟨⟨BitVec.ofInt 16 i⟩⟩
|
||||
@[extern "lean_int16_of_nat"]
|
||||
def Int16.ofNat (n : @& Nat) : Int16 := ⟨⟨BitVec.ofNat 16 n⟩⟩
|
||||
abbrev Int.toInt16 := Int16.ofInt
|
||||
abbrev Nat.toInt16 := Int16.ofNat
|
||||
@[extern "lean_int16_to_int"]
|
||||
def Int16.toInt (i : Int16) : Int := i.toBitVec.toInt
|
||||
/--
|
||||
This function has the same behavior as `Int.toNat` for negative numbers.
|
||||
If you want to obtain the 2's complement representation use `toBitVec`.
|
||||
-/
|
||||
@[inline] def Int16.toNat (i : Int16) : Nat := i.toInt.toNat
|
||||
@[extern "lean_int16_to_int8"]
|
||||
def Int16.toInt8 (a : Int16) : Int8 := ⟨⟨a.toBitVec.signExtend 8⟩⟩
|
||||
@[extern "lean_int8_to_int16"]
|
||||
def Int8.toInt16 (a : Int8) : Int16 := ⟨⟨a.toBitVec.signExtend 16⟩⟩
|
||||
@[extern "lean_int16_neg"]
|
||||
def Int16.neg (i : Int16) : Int16 := ⟨⟨-i.toBitVec⟩⟩
|
||||
|
||||
instance : ToString Int16 where
|
||||
toString i := toString i.toInt
|
||||
|
||||
instance : OfNat Int16 n := ⟨Int16.ofNat n⟩
|
||||
instance : Neg Int16 where
|
||||
neg := Int16.neg
|
||||
|
||||
@[extern "lean_int16_add"]
|
||||
def Int16.add (a b : Int16) : Int16 := ⟨⟨a.toBitVec + b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_sub"]
|
||||
def Int16.sub (a b : Int16) : Int16 := ⟨⟨a.toBitVec - b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_mul"]
|
||||
def Int16.mul (a b : Int16) : Int16 := ⟨⟨a.toBitVec * b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_div"]
|
||||
def Int16.div (a b : Int16) : Int16 := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_mod"]
|
||||
def Int16.mod (a b : Int16) : Int16 := ⟨⟨BitVec.srem a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_land"]
|
||||
def Int16.land (a b : Int16) : Int16 := ⟨⟨a.toBitVec &&& b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_lor"]
|
||||
def Int16.lor (a b : Int16) : Int16 := ⟨⟨a.toBitVec ||| b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_xor"]
|
||||
def Int16.xor (a b : Int16) : Int16 := ⟨⟨a.toBitVec ^^^ b.toBitVec⟩⟩
|
||||
@[extern "lean_int16_shift_left"]
|
||||
def Int16.shiftLeft (a b : Int16) : Int16 := ⟨⟨a.toBitVec <<< (b.toBitVec.smod 16)⟩⟩
|
||||
@[extern "lean_int16_shift_right"]
|
||||
def Int16.shiftRight (a b : Int16) : Int16 := ⟨⟨BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 16)⟩⟩
|
||||
@[extern "lean_int16_complement"]
|
||||
def Int16.complement (a : Int16) : Int16 := ⟨⟨~~~a.toBitVec⟩⟩
|
||||
|
||||
@[extern "lean_int16_dec_eq"]
|
||||
def Int16.decEq (a b : Int16) : Decidable (a = b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ =>
|
||||
if h : n = m then
|
||||
isTrue <| h ▸ rfl
|
||||
else
|
||||
isFalse (fun h' => Int16.noConfusion h' (fun h' => absurd h' h))
|
||||
|
||||
def Int16.lt (a b : Int16) : Prop := a.toBitVec.slt b.toBitVec
|
||||
def Int16.le (a b : Int16) : Prop := a.toBitVec.sle b.toBitVec
|
||||
|
||||
instance : Inhabited Int16 where
|
||||
default := 0
|
||||
|
||||
instance : Add Int16 := ⟨Int16.add⟩
|
||||
instance : Sub Int16 := ⟨Int16.sub⟩
|
||||
instance : Mul Int16 := ⟨Int16.mul⟩
|
||||
instance : Mod Int16 := ⟨Int16.mod⟩
|
||||
instance : Div Int16 := ⟨Int16.div⟩
|
||||
instance : LT Int16 := ⟨Int16.lt⟩
|
||||
instance : LE Int16 := ⟨Int16.le⟩
|
||||
instance : Complement Int16 := ⟨Int16.complement⟩
|
||||
instance : AndOp Int16 := ⟨Int16.land⟩
|
||||
instance : OrOp Int16 := ⟨Int16.lor⟩
|
||||
instance : Xor Int16 := ⟨Int16.xor⟩
|
||||
instance : ShiftLeft Int16 := ⟨Int16.shiftLeft⟩
|
||||
instance : ShiftRight Int16 := ⟨Int16.shiftRight⟩
|
||||
instance : DecidableEq Int16 := Int16.decEq
|
||||
|
||||
@[extern "lean_int16_dec_lt"]
|
||||
def Int16.decLt (a b : Int16) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@[extern "lean_int16_dec_le"]
|
||||
def Int16.decLe (a b : Int16) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : Int16) : Decidable (a < b) := Int16.decLt a b
|
||||
instance (a b : Int16) : Decidable (a ≤ b) := Int16.decLe a b
|
||||
instance : Max Int16 := maxOfLe
|
||||
instance : Min Int16 := minOfLe
|
||||
|
||||
/-- The size of type `Int32`, that is, `2^32 = 4294967296`. -/
|
||||
abbrev Int32.size : Nat := 4294967296
|
||||
|
||||
/--
|
||||
Obtain the `BitVec` that contains the 2's complement representation of the `Int32`.
|
||||
-/
|
||||
@[inline] def Int32.toBitVec (x : Int32) : BitVec 32 := x.toUInt32.toBitVec
|
||||
|
||||
@[extern "lean_int32_of_int"]
|
||||
def Int32.ofInt (i : @& Int) : Int32 := ⟨⟨BitVec.ofInt 32 i⟩⟩
|
||||
@[extern "lean_int32_of_nat"]
|
||||
def Int32.ofNat (n : @& Nat) : Int32 := ⟨⟨BitVec.ofNat 32 n⟩⟩
|
||||
abbrev Int.toInt32 := Int32.ofInt
|
||||
abbrev Nat.toInt32 := Int32.ofNat
|
||||
@[extern "lean_int32_to_int"]
|
||||
def Int32.toInt (i : Int32) : Int := i.toBitVec.toInt
|
||||
/--
|
||||
This function has the same behavior as `Int.toNat` for negative numbers.
|
||||
If you want to obtain the 2's complement representation use `toBitVec`.
|
||||
-/
|
||||
@[inline] def Int32.toNat (i : Int32) : Nat := i.toInt.toNat
|
||||
@[extern "lean_int32_to_int8"]
|
||||
def Int32.toInt8 (a : Int32) : Int8 := ⟨⟨a.toBitVec.signExtend 8⟩⟩
|
||||
@[extern "lean_int32_to_int16"]
|
||||
def Int32.toInt16 (a : Int32) : Int16 := ⟨⟨a.toBitVec.signExtend 16⟩⟩
|
||||
@[extern "lean_int8_to_int32"]
|
||||
def Int8.toInt32 (a : Int8) : Int32 := ⟨⟨a.toBitVec.signExtend 32⟩⟩
|
||||
@[extern "lean_int16_to_int32"]
|
||||
def Int16.toInt32 (a : Int16) : Int32 := ⟨⟨a.toBitVec.signExtend 32⟩⟩
|
||||
@[extern "lean_int32_neg"]
|
||||
def Int32.neg (i : Int32) : Int32 := ⟨⟨-i.toBitVec⟩⟩
|
||||
|
||||
instance : ToString Int32 where
|
||||
toString i := toString i.toInt
|
||||
|
||||
instance : OfNat Int32 n := ⟨Int32.ofNat n⟩
|
||||
instance : Neg Int32 where
|
||||
neg := Int32.neg
|
||||
|
||||
@[extern "lean_int32_add"]
|
||||
def Int32.add (a b : Int32) : Int32 := ⟨⟨a.toBitVec + b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_sub"]
|
||||
def Int32.sub (a b : Int32) : Int32 := ⟨⟨a.toBitVec - b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_mul"]
|
||||
def Int32.mul (a b : Int32) : Int32 := ⟨⟨a.toBitVec * b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_div"]
|
||||
def Int32.div (a b : Int32) : Int32 := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_mod"]
|
||||
def Int32.mod (a b : Int32) : Int32 := ⟨⟨BitVec.srem a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_land"]
|
||||
def Int32.land (a b : Int32) : Int32 := ⟨⟨a.toBitVec &&& b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_lor"]
|
||||
def Int32.lor (a b : Int32) : Int32 := ⟨⟨a.toBitVec ||| b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_xor"]
|
||||
def Int32.xor (a b : Int32) : Int32 := ⟨⟨a.toBitVec ^^^ b.toBitVec⟩⟩
|
||||
@[extern "lean_int32_shift_left"]
|
||||
def Int32.shiftLeft (a b : Int32) : Int32 := ⟨⟨a.toBitVec <<< (b.toBitVec.smod 32)⟩⟩
|
||||
@[extern "lean_int32_shift_right"]
|
||||
def Int32.shiftRight (a b : Int32) : Int32 := ⟨⟨BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 32)⟩⟩
|
||||
@[extern "lean_int32_complement"]
|
||||
def Int32.complement (a : Int32) : Int32 := ⟨⟨~~~a.toBitVec⟩⟩
|
||||
|
||||
@[extern "lean_int32_dec_eq"]
|
||||
def Int32.decEq (a b : Int32) : Decidable (a = b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ =>
|
||||
if h : n = m then
|
||||
isTrue <| h ▸ rfl
|
||||
else
|
||||
isFalse (fun h' => Int32.noConfusion h' (fun h' => absurd h' h))
|
||||
|
||||
def Int32.lt (a b : Int32) : Prop := a.toBitVec.slt b.toBitVec
|
||||
def Int32.le (a b : Int32) : Prop := a.toBitVec.sle b.toBitVec
|
||||
|
||||
instance : Inhabited Int32 where
|
||||
default := 0
|
||||
|
||||
instance : Add Int32 := ⟨Int32.add⟩
|
||||
instance : Sub Int32 := ⟨Int32.sub⟩
|
||||
instance : Mul Int32 := ⟨Int32.mul⟩
|
||||
instance : Mod Int32 := ⟨Int32.mod⟩
|
||||
instance : Div Int32 := ⟨Int32.div⟩
|
||||
instance : LT Int32 := ⟨Int32.lt⟩
|
||||
instance : LE Int32 := ⟨Int32.le⟩
|
||||
instance : Complement Int32 := ⟨Int32.complement⟩
|
||||
instance : AndOp Int32 := ⟨Int32.land⟩
|
||||
instance : OrOp Int32 := ⟨Int32.lor⟩
|
||||
instance : Xor Int32 := ⟨Int32.xor⟩
|
||||
instance : ShiftLeft Int32 := ⟨Int32.shiftLeft⟩
|
||||
instance : ShiftRight Int32 := ⟨Int32.shiftRight⟩
|
||||
instance : DecidableEq Int32 := Int32.decEq
|
||||
|
||||
@[extern "lean_int32_dec_lt"]
|
||||
def Int32.decLt (a b : Int32) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@[extern "lean_int32_dec_le"]
|
||||
def Int32.decLe (a b : Int32) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : Int32) : Decidable (a < b) := Int32.decLt a b
|
||||
instance (a b : Int32) : Decidable (a ≤ b) := Int32.decLe a b
|
||||
instance : Max Int32 := maxOfLe
|
||||
instance : Min Int32 := minOfLe
|
||||
|
||||
/-- The size of type `Int64`, that is, `2^64 = 18446744073709551616`. -/
|
||||
abbrev Int64.size : Nat := 18446744073709551616
|
||||
|
||||
/--
|
||||
Obtain the `BitVec` that contains the 2's complement representation of the `Int64`.
|
||||
-/
|
||||
@[inline] def Int64.toBitVec (x : Int64) : BitVec 64 := x.toUInt64.toBitVec
|
||||
|
||||
@[extern "lean_int64_of_int"]
|
||||
def Int64.ofInt (i : @& Int) : Int64 := ⟨⟨BitVec.ofInt 64 i⟩⟩
|
||||
@[extern "lean_int64_of_nat"]
|
||||
def Int64.ofNat (n : @& Nat) : Int64 := ⟨⟨BitVec.ofNat 64 n⟩⟩
|
||||
abbrev Int.toInt64 := Int64.ofInt
|
||||
abbrev Nat.toInt64 := Int64.ofNat
|
||||
@[extern "lean_int64_to_int_sint"]
|
||||
def Int64.toInt (i : Int64) : Int := i.toBitVec.toInt
|
||||
/--
|
||||
This function has the same behavior as `Int.toNat` for negative numbers.
|
||||
If you want to obtain the 2's complement representation use `toBitVec`.
|
||||
-/
|
||||
@[inline] def Int64.toNat (i : Int64) : Nat := i.toInt.toNat
|
||||
@[extern "lean_int64_to_int8"]
|
||||
def Int64.toInt8 (a : Int64) : Int8 := ⟨⟨a.toBitVec.signExtend 8⟩⟩
|
||||
@[extern "lean_int64_to_int16"]
|
||||
def Int64.toInt16 (a : Int64) : Int16 := ⟨⟨a.toBitVec.signExtend 16⟩⟩
|
||||
@[extern "lean_int64_to_int32"]
|
||||
def Int64.toInt32 (a : Int64) : Int32 := ⟨⟨a.toBitVec.signExtend 32⟩⟩
|
||||
@[extern "lean_int8_to_int64"]
|
||||
def Int8.toInt64 (a : Int8) : Int64 := ⟨⟨a.toBitVec.signExtend 64⟩⟩
|
||||
@[extern "lean_int16_to_int64"]
|
||||
def Int16.toInt64 (a : Int16) : Int64 := ⟨⟨a.toBitVec.signExtend 64⟩⟩
|
||||
@[extern "lean_int32_to_int64"]
|
||||
def Int32.toInt64 (a : Int32) : Int64 := ⟨⟨a.toBitVec.signExtend 64⟩⟩
|
||||
@[extern "lean_int64_neg"]
|
||||
def Int64.neg (i : Int64) : Int64 := ⟨⟨-i.toBitVec⟩⟩
|
||||
|
||||
instance : ToString Int64 where
|
||||
toString i := toString i.toInt
|
||||
|
||||
instance : OfNat Int64 n := ⟨Int64.ofNat n⟩
|
||||
instance : Neg Int64 where
|
||||
neg := Int64.neg
|
||||
|
||||
@[extern "lean_int64_add"]
|
||||
def Int64.add (a b : Int64) : Int64 := ⟨⟨a.toBitVec + b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_sub"]
|
||||
def Int64.sub (a b : Int64) : Int64 := ⟨⟨a.toBitVec - b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_mul"]
|
||||
def Int64.mul (a b : Int64) : Int64 := ⟨⟨a.toBitVec * b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_div"]
|
||||
def Int64.div (a b : Int64) : Int64 := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_mod"]
|
||||
def Int64.mod (a b : Int64) : Int64 := ⟨⟨BitVec.srem a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_land"]
|
||||
def Int64.land (a b : Int64) : Int64 := ⟨⟨a.toBitVec &&& b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_lor"]
|
||||
def Int64.lor (a b : Int64) : Int64 := ⟨⟨a.toBitVec ||| b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_xor"]
|
||||
def Int64.xor (a b : Int64) : Int64 := ⟨⟨a.toBitVec ^^^ b.toBitVec⟩⟩
|
||||
@[extern "lean_int64_shift_left"]
|
||||
def Int64.shiftLeft (a b : Int64) : Int64 := ⟨⟨a.toBitVec <<< (b.toBitVec.smod 64)⟩⟩
|
||||
@[extern "lean_int64_shift_right"]
|
||||
def Int64.shiftRight (a b : Int64) : Int64 := ⟨⟨BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod 64)⟩⟩
|
||||
@[extern "lean_int64_complement"]
|
||||
def Int64.complement (a : Int64) : Int64 := ⟨⟨~~~a.toBitVec⟩⟩
|
||||
|
||||
@[extern "lean_int64_dec_eq"]
|
||||
def Int64.decEq (a b : Int64) : Decidable (a = b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ =>
|
||||
if h : n = m then
|
||||
isTrue <| h ▸ rfl
|
||||
else
|
||||
isFalse (fun h' => Int64.noConfusion h' (fun h' => absurd h' h))
|
||||
|
||||
def Int64.lt (a b : Int64) : Prop := a.toBitVec.slt b.toBitVec
|
||||
def Int64.le (a b : Int64) : Prop := a.toBitVec.sle b.toBitVec
|
||||
|
||||
instance : Inhabited Int64 where
|
||||
default := 0
|
||||
|
||||
instance : Add Int64 := ⟨Int64.add⟩
|
||||
instance : Sub Int64 := ⟨Int64.sub⟩
|
||||
instance : Mul Int64 := ⟨Int64.mul⟩
|
||||
instance : Mod Int64 := ⟨Int64.mod⟩
|
||||
instance : Div Int64 := ⟨Int64.div⟩
|
||||
instance : LT Int64 := ⟨Int64.lt⟩
|
||||
instance : LE Int64 := ⟨Int64.le⟩
|
||||
instance : Complement Int64 := ⟨Int64.complement⟩
|
||||
instance : AndOp Int64 := ⟨Int64.land⟩
|
||||
instance : OrOp Int64 := ⟨Int64.lor⟩
|
||||
instance : Xor Int64 := ⟨Int64.xor⟩
|
||||
instance : ShiftLeft Int64 := ⟨Int64.shiftLeft⟩
|
||||
instance : ShiftRight Int64 := ⟨Int64.shiftRight⟩
|
||||
instance : DecidableEq Int64 := Int64.decEq
|
||||
|
||||
@[extern "lean_int64_dec_lt"]
|
||||
def Int64.decLt (a b : Int64) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@[extern "lean_int64_dec_le"]
|
||||
def Int64.decLe (a b : Int64) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : Int64) : Decidable (a < b) := Int64.decLt a b
|
||||
instance (a b : Int64) : Decidable (a ≤ b) := Int64.decLe a b
|
||||
instance : Max Int64 := maxOfLe
|
||||
instance : Min Int64 := minOfLe
|
||||
|
||||
/-- The size of type `ISize`, that is, `2^System.Platform.numBits`. -/
|
||||
abbrev ISize.size : Nat := 2^System.Platform.numBits
|
||||
|
||||
/--
|
||||
Obtain the `BitVec` that contains the 2's complement representation of the `ISize`.
|
||||
-/
|
||||
@[inline] def ISize.toBitVec (x : ISize) : BitVec System.Platform.numBits := x.toUSize.toBitVec
|
||||
|
||||
@[extern "lean_isize_of_int"]
|
||||
def ISize.ofInt (i : @& Int) : ISize := ⟨⟨BitVec.ofInt System.Platform.numBits i⟩⟩
|
||||
@[extern "lean_isize_of_nat"]
|
||||
def ISize.ofNat (n : @& Nat) : ISize := ⟨⟨BitVec.ofNat System.Platform.numBits n⟩⟩
|
||||
abbrev Int.toISize := ISize.ofInt
|
||||
abbrev Nat.toISize := ISize.ofNat
|
||||
@[extern "lean_isize_to_int"]
|
||||
def ISize.toInt (i : ISize) : Int := i.toBitVec.toInt
|
||||
/--
|
||||
This function has the same behavior as `Int.toNat` for negative numbers.
|
||||
If you want to obtain the 2's complement representation use `toBitVec`.
|
||||
-/
|
||||
@[inline] def ISize.toNat (i : ISize) : Nat := i.toInt.toNat
|
||||
@[extern "lean_isize_to_int32"]
|
||||
def ISize.toInt32 (a : ISize) : Int32 := ⟨⟨a.toBitVec.signExtend 32⟩⟩
|
||||
/--
|
||||
Upcast `ISize` to `Int64`. This function is losless as `ISize` is either `Int32` or `Int64`.
|
||||
-/
|
||||
@[extern "lean_isize_to_int64"]
|
||||
def ISize.toInt64 (a : ISize) : Int64 := ⟨⟨a.toBitVec.signExtend 64⟩⟩
|
||||
/--
|
||||
Upcast `Int32` to `ISize`. This function is losless as `ISize` is either `Int32` or `Int64`.
|
||||
-/
|
||||
@[extern "lean_int32_to_isize"]
|
||||
def Int32.toISize (a : Int32) : ISize := ⟨⟨a.toBitVec.signExtend System.Platform.numBits⟩⟩
|
||||
@[extern "lean_int64_to_isize"]
|
||||
def Int64.toISize (a : Int64) : ISize := ⟨⟨a.toBitVec.signExtend System.Platform.numBits⟩⟩
|
||||
@[extern "lean_isize_neg"]
|
||||
def ISize.neg (i : ISize) : ISize := ⟨⟨-i.toBitVec⟩⟩
|
||||
|
||||
instance : ToString ISize where
|
||||
toString i := toString i.toInt
|
||||
|
||||
instance : OfNat ISize n := ⟨ISize.ofNat n⟩
|
||||
instance : Neg ISize where
|
||||
neg := ISize.neg
|
||||
|
||||
@[extern "lean_isize_add"]
|
||||
def ISize.add (a b : ISize) : ISize := ⟨⟨a.toBitVec + b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_sub"]
|
||||
def ISize.sub (a b : ISize) : ISize := ⟨⟨a.toBitVec - b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_mul"]
|
||||
def ISize.mul (a b : ISize) : ISize := ⟨⟨a.toBitVec * b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_div"]
|
||||
def ISize.div (a b : ISize) : ISize := ⟨⟨BitVec.sdiv a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_mod"]
|
||||
def ISize.mod (a b : ISize) : ISize := ⟨⟨BitVec.srem a.toBitVec b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_land"]
|
||||
def ISize.land (a b : ISize) : ISize := ⟨⟨a.toBitVec &&& b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_lor"]
|
||||
def ISize.lor (a b : ISize) : ISize := ⟨⟨a.toBitVec ||| b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_xor"]
|
||||
def ISize.xor (a b : ISize) : ISize := ⟨⟨a.toBitVec ^^^ b.toBitVec⟩⟩
|
||||
@[extern "lean_isize_shift_left"]
|
||||
def ISize.shiftLeft (a b : ISize) : ISize := ⟨⟨a.toBitVec <<< (b.toBitVec.smod System.Platform.numBits)⟩⟩
|
||||
@[extern "lean_isize_shift_right"]
|
||||
def ISize.shiftRight (a b : ISize) : ISize := ⟨⟨BitVec.sshiftRight' a.toBitVec (b.toBitVec.smod System.Platform.numBits)⟩⟩
|
||||
@[extern "lean_isize_complement"]
|
||||
def ISize.complement (a : ISize) : ISize := ⟨⟨~~~a.toBitVec⟩⟩
|
||||
|
||||
@[extern "lean_isize_dec_eq"]
|
||||
def ISize.decEq (a b : ISize) : Decidable (a = b) :=
|
||||
match a, b with
|
||||
| ⟨n⟩, ⟨m⟩ =>
|
||||
if h : n = m then
|
||||
isTrue <| h ▸ rfl
|
||||
else
|
||||
isFalse (fun h' => ISize.noConfusion h' (fun h' => absurd h' h))
|
||||
|
||||
def ISize.lt (a b : ISize) : Prop := a.toBitVec.slt b.toBitVec
|
||||
def ISize.le (a b : ISize) : Prop := a.toBitVec.sle b.toBitVec
|
||||
|
||||
instance : Inhabited ISize where
|
||||
default := 0
|
||||
|
||||
instance : Add ISize := ⟨ISize.add⟩
|
||||
instance : Sub ISize := ⟨ISize.sub⟩
|
||||
instance : Mul ISize := ⟨ISize.mul⟩
|
||||
instance : Mod ISize := ⟨ISize.mod⟩
|
||||
instance : Div ISize := ⟨ISize.div⟩
|
||||
instance : LT ISize := ⟨ISize.lt⟩
|
||||
instance : LE ISize := ⟨ISize.le⟩
|
||||
instance : Complement ISize := ⟨ISize.complement⟩
|
||||
instance : AndOp ISize := ⟨ISize.land⟩
|
||||
instance : OrOp ISize := ⟨ISize.lor⟩
|
||||
instance : Xor ISize := ⟨ISize.xor⟩
|
||||
instance : ShiftLeft ISize := ⟨ISize.shiftLeft⟩
|
||||
instance : ShiftRight ISize := ⟨ISize.shiftRight⟩
|
||||
instance : DecidableEq ISize := ISize.decEq
|
||||
|
||||
@[extern "lean_isize_dec_lt"]
|
||||
def ISize.decLt (a b : ISize) : Decidable (a < b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.slt b.toBitVec))
|
||||
|
||||
@[extern "lean_isize_dec_le"]
|
||||
def ISize.decLe (a b : ISize) : Decidable (a ≤ b) :=
|
||||
inferInstanceAs (Decidable (a.toBitVec.sle b.toBitVec))
|
||||
|
||||
instance (a b : ISize) : Decidable (a < b) := ISize.decLt a b
|
||||
instance (a b : ISize) : Decidable (a ≤ b) := ISize.decLe a b
|
||||
instance : Max ISize := maxOfLe
|
||||
instance : Min ISize := minOfLe
|
||||
|
||||
@@ -211,10 +211,13 @@ instance : GetElem (List α) Nat α fun as i => i < as.length where
|
||||
| _ :: _, 0, _ => .head ..
|
||||
| _ :: l, _+1, _ => .tail _ (getElem_mem (l := l) ..)
|
||||
|
||||
theorem get_drop_eq_drop (as : List α) (i : Nat) (h : i < as.length) : as[i] :: as.drop (i+1) = as.drop i :=
|
||||
theorem getElem_cons_drop_succ_eq_drop {as : List α} {i : Nat} (h : i < as.length) :
|
||||
as[i] :: as.drop (i+1) = as.drop i :=
|
||||
match as, i with
|
||||
| _::_, 0 => rfl
|
||||
| _::_, i+1 => get_drop_eq_drop _ i _
|
||||
| _::_, i+1 => getElem_cons_drop_succ_eq_drop (i := i) _
|
||||
|
||||
@[deprecated (since := "2024-11-05")] abbrev get_drop_eq_drop := @getElem_cons_drop_succ_eq_drop
|
||||
|
||||
end List
|
||||
|
||||
|
||||
@@ -263,7 +263,7 @@ theorem Bool.not_eq_false' (b : Bool) : ((!b) = false) = (b = true) := by simp
|
||||
⟨of_decide_eq_false, decide_eq_false⟩
|
||||
|
||||
@[simp] theorem decide_not [g : Decidable p] [h : Decidable (Not p)] : decide (Not p) = !(decide p) := by
|
||||
cases g <;> (rename_i gp; simp [gp]; rfl)
|
||||
cases g <;> (rename_i gp; simp [gp])
|
||||
theorem not_decide_eq_true [h : Decidable p] : ((!decide p) = true) = ¬ p := by simp
|
||||
|
||||
@[simp] theorem heq_eq_eq (a b : α) : HEq a b = (a = b) := propext <| Iff.intro eq_of_heq heq_of_eq
|
||||
@@ -277,8 +277,10 @@ theorem beq_self_eq_true' [DecidableEq α] (a : α) : (a == a) = true := by simp
|
||||
@[simp] theorem bne_self_eq_false [BEq α] [LawfulBEq α] (a : α) : (a != a) = false := by simp [bne]
|
||||
theorem bne_self_eq_false' [DecidableEq α] (a : α) : (a != a) = false := by simp
|
||||
|
||||
@[simp] theorem decide_False : decide False = false := rfl
|
||||
@[simp] theorem decide_True : decide True = true := rfl
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated decide_false (since := "2024-11-05")] abbrev decide_False := decide_false
|
||||
set_option linter.missingDocs false in
|
||||
@[deprecated decide_true (since := "2024-11-05")] abbrev decide_True := decide_true
|
||||
|
||||
@[simp] theorem bne_iff_ne [BEq α] [LawfulBEq α] {a b : α} : a != b ↔ a ≠ b := by
|
||||
simp [bne]; rw [← beq_iff_eq (a := a) (b := b)]; simp [-beq_iff_eq]
|
||||
|
||||
@@ -272,12 +272,20 @@ macro nextTk:"next " args:binderIdent* arrowTk:" => " tac:tacticSeq : tactic =>
|
||||
-- Limit ref variability for incrementality; see Note [Incremental Macros]
|
||||
withRef arrowTk `(tactic| case%$nextTk _ $args* =>%$arrowTk $tac)
|
||||
|
||||
/-- `all_goals tac` runs `tac` on each goal, concatenating the resulting goals, if any. -/
|
||||
/--
|
||||
`all_goals tac` runs `tac` on each goal, concatenating the resulting goals.
|
||||
If the tactic fails on any goal, the entire `all_goals` tactic fails.
|
||||
|
||||
See also `any_goals tac`.
|
||||
-/
|
||||
syntax (name := allGoals) "all_goals " tacticSeq : tactic
|
||||
|
||||
/--
|
||||
`any_goals tac` applies the tactic `tac` to every goal, and succeeds if at
|
||||
least one application succeeds.
|
||||
`any_goals tac` applies the tactic `tac` to every goal,
|
||||
concating the resulting goals for successful tactic applications.
|
||||
If the tactic fails on all of the goals, the entire `any_goals` tactic fails.
|
||||
|
||||
This tactic is like `all_goals try tac` except that it fails if none of the applications of `tac` succeeds.
|
||||
-/
|
||||
syntax (name := anyGoals) "any_goals " tacticSeq : tactic
|
||||
|
||||
|
||||
@@ -957,7 +957,7 @@ where
|
||||
let mut s : CollectFVars.State := {}
|
||||
for discr in discrs do
|
||||
s := collectFVars s (← instantiateMVars (← inferType discr))
|
||||
let (indicesFVar, indicesNonFVar) := indices.split Expr.isFVar
|
||||
let (indicesFVar, indicesNonFVar) := indices.partition Expr.isFVar
|
||||
let indicesFVar := indicesFVar.map Expr.fvarId!
|
||||
let mut toAdd := #[]
|
||||
for fvarId in s.fvarSet.toList do
|
||||
|
||||
@@ -35,9 +35,13 @@ Reconstruct bit by bit which value expression must have had which `BitVec` value
|
||||
expression - pair values.
|
||||
-/
|
||||
def reconstructCounterExample (var2Cnf : Std.HashMap BVBit Nat) (assignment : Array (Bool × Nat))
|
||||
(aigSize : Nat) (atomsAssignment : Std.HashMap Nat (Nat × Expr)) :
|
||||
(aigSize : Nat) (atomsAssignment : Std.HashMap Nat (Nat × Expr × Bool)) :
|
||||
Array (Expr × BVExpr.PackedBitVec) := Id.run do
|
||||
let mut sparseMap : Std.HashMap Nat (RBMap Nat Bool Ord.compare) := {}
|
||||
let filter bvBit _ :=
|
||||
let (_, _, synthetic) := atomsAssignment.get! bvBit.var
|
||||
!synthetic
|
||||
let var2Cnf := var2Cnf.filter filter
|
||||
for (bitVar, cnfVar) in var2Cnf.toArray do
|
||||
/-
|
||||
The setup of the variables in CNF is as follows:
|
||||
@@ -70,7 +74,7 @@ def reconstructCounterExample (var2Cnf : Std.HashMap BVBit Nat) (assignment : Ar
|
||||
if bitValue then
|
||||
value := value ||| (1 <<< currentBit)
|
||||
currentBit := currentBit + 1
|
||||
let atomExpr := atomsAssignment.get! bitVecVar |>.snd
|
||||
let (_, atomExpr, _) := atomsAssignment.get! bitVecVar
|
||||
finalMap := finalMap.push (atomExpr, ⟨BitVec.ofNat currentBit value⟩)
|
||||
return finalMap
|
||||
|
||||
@@ -101,7 +105,7 @@ structure UnsatProver.Result where
|
||||
proof : Expr
|
||||
lratCert : LratCert
|
||||
|
||||
abbrev UnsatProver := MVarId → ReflectionResult → Std.HashMap Nat (Nat × Expr) →
|
||||
abbrev UnsatProver := MVarId → ReflectionResult → Std.HashMap Nat (Nat × Expr × Bool) →
|
||||
MetaM (Except CounterExample UnsatProver.Result)
|
||||
|
||||
/--
|
||||
@@ -183,7 +187,7 @@ def explainCounterExampleQuality (counterExample : CounterExample) : MetaM Messa
|
||||
return err
|
||||
|
||||
def lratBitblaster (goal : MVarId) (cfg : TacticContext) (reflectionResult : ReflectionResult)
|
||||
(atomsAssignment : Std.HashMap Nat (Nat × Expr)) :
|
||||
(atomsAssignment : Std.HashMap Nat (Nat × Expr × Bool)) :
|
||||
MetaM (Except CounterExample UnsatProver.Result) := do
|
||||
let bvExpr := reflectionResult.bvExpr
|
||||
let entry ←
|
||||
@@ -253,7 +257,8 @@ def closeWithBVReflection (g : MVarId) (unsatProver : UnsatProver) :
|
||||
reflectBV g
|
||||
trace[Meta.Tactic.bv] "Reflected bv logical expression: {reflectionResult.bvExpr}"
|
||||
|
||||
let atomsPairs := (← getThe State).atoms.toList.map (fun (expr, ⟨width, ident⟩) => (ident, (width, expr)))
|
||||
let flipper := (fun (expr, {width, atomNumber, synthetic}) => (atomNumber, (width, expr, synthetic)))
|
||||
let atomsPairs := (← getThe State).atoms.toList.map flipper
|
||||
let atomsAssignment := Std.HashMap.ofList atomsPairs
|
||||
match ← unsatProver g reflectionResult atomsAssignment with
|
||||
| .ok ⟨bvExprUnsat, cert⟩ =>
|
||||
|
||||
@@ -107,6 +107,25 @@ where
|
||||
|
||||
open Lean.Meta
|
||||
|
||||
/--
|
||||
A `BitVec` atom.
|
||||
-/
|
||||
structure Atom where
|
||||
/--
|
||||
The width of the `BitVec` that is being abstracted.
|
||||
-/
|
||||
width : Nat
|
||||
/--
|
||||
A unique numeric identifier for the atom.
|
||||
-/
|
||||
atomNumber : Nat
|
||||
/--
|
||||
Whether the atom is synthetic. The effect of this is that values for this atom are not considered
|
||||
for the counter example deriviation. This is for example useful when we introduce an atom over
|
||||
an expression, together with additional lemmas that fully describe the behavior of the atom.
|
||||
-/
|
||||
synthetic : Bool
|
||||
|
||||
/--
|
||||
The state of the reflection monad
|
||||
-/
|
||||
@@ -115,7 +134,7 @@ structure State where
|
||||
The atoms encountered so far. Saved as a map from `BitVec` expressions to a (width, atomNumber)
|
||||
pair.
|
||||
-/
|
||||
atoms : Std.HashMap Expr (Nat × Nat) := {}
|
||||
atoms : Std.HashMap Expr Atom := {}
|
||||
/--
|
||||
A cache for `atomsAssignment`.
|
||||
-/
|
||||
@@ -208,8 +227,8 @@ def run (m : M α) : MetaM α :=
|
||||
Retrieve the atoms as pairs of their width and expression.
|
||||
-/
|
||||
def atoms : M (List (Nat × Expr)) := do
|
||||
let sortedAtoms := (← getThe State).atoms.toArray.qsort (·.2.2 < ·.2.2)
|
||||
return sortedAtoms.map (fun (expr, width, _) => (width, expr)) |>.toList
|
||||
let sortedAtoms := (← getThe State).atoms.toArray.qsort (·.2.atomNumber < ·.2.atomNumber)
|
||||
return sortedAtoms.map (fun (expr, {width, ..}) => (width, expr)) |>.toList
|
||||
|
||||
/--
|
||||
Retrieve a `BitVec.Assignment` representing the atoms we found so far.
|
||||
@@ -220,16 +239,17 @@ def atomsAssignment : M Expr := do
|
||||
/--
|
||||
Look up an expression in the atoms, recording it if it has not previously appeared.
|
||||
-/
|
||||
def lookup (e : Expr) (width : Nat) : M Nat := do
|
||||
def lookup (e : Expr) (width : Nat) (synthetic : Bool) : M Nat := do
|
||||
match (← getThe State).atoms[e]? with
|
||||
| some (width', ident) =>
|
||||
if width != width' then
|
||||
| some atom =>
|
||||
if width != atom.width then
|
||||
panic! "The same atom occurs with different widths, this is a bug"
|
||||
return ident
|
||||
return atom.atomNumber
|
||||
| none =>
|
||||
trace[Meta.Tactic.bv] "New atom of width {width}: {e}"
|
||||
trace[Meta.Tactic.bv] "New atom of width {width}, synthetic? {synthetic}: {e}"
|
||||
let ident ← modifyGetThe State fun s =>
|
||||
(s.atoms.size, { s with atoms := s.atoms.insert e (width, s.atoms.size) })
|
||||
let newAtom := { width, synthetic, atomNumber := s.atoms.size}
|
||||
(s.atoms.size, { s with atoms := s.atoms.insert e newAtom })
|
||||
updateAtomsAssignment
|
||||
return ident
|
||||
where
|
||||
|
||||
@@ -32,10 +32,10 @@ def mkBVRefl (w : Nat) (expr : Expr) : Expr :=
|
||||
expr
|
||||
|
||||
/--
|
||||
Register `e` as an atom of width `width`.
|
||||
Register `e` as an atom of `width` that might potentially be `synthetic`.
|
||||
-/
|
||||
def mkAtom (e : Expr) (width : Nat) : M ReifiedBVExpr := do
|
||||
let ident ← M.lookup e width
|
||||
def mkAtom (e : Expr) (width : Nat) (synthetic : Bool) : M ReifiedBVExpr := do
|
||||
let ident ← M.lookup e width synthetic
|
||||
let expr := mkApp2 (mkConst ``BVExpr.var) (toExpr width) (toExpr ident)
|
||||
let proof := do
|
||||
let evalExpr ← mkEvalExpr width expr
|
||||
@@ -55,13 +55,13 @@ def getNatOrBvValue? (ty : Expr) (expr : Expr) : M (Option Nat) := do
|
||||
| _ => return none
|
||||
|
||||
/--
|
||||
Construct an uninterpreted `BitVec` atom from `x`.
|
||||
Construct an uninterpreted `BitVec` atom from `x`, potentially `synthetic`.
|
||||
-/
|
||||
def bitVecAtom (x : Expr) : M (Option ReifiedBVExpr) := do
|
||||
def bitVecAtom (x : Expr) (synthetic : Bool) : M (Option ReifiedBVExpr) := do
|
||||
let t ← instantiateMVars (← whnfR (← inferType x))
|
||||
let_expr BitVec widthExpr := t | return none
|
||||
let some width ← getNatValue? widthExpr | return none
|
||||
let atom ← mkAtom x width
|
||||
let atom ← mkAtom x width synthetic
|
||||
return some atom
|
||||
|
||||
/--
|
||||
|
||||
@@ -31,7 +31,7 @@ def boolAtom (t : Expr) : M (Option ReifiedBVPred) := do
|
||||
-/
|
||||
let ty ← inferType t
|
||||
let_expr Bool := ty | return none
|
||||
let atom ← ReifiedBVExpr.mkAtom (mkApp (mkConst ``BitVec.ofBool) t) 1
|
||||
let atom ← ReifiedBVExpr.mkAtom (mkApp (mkConst ``BitVec.ofBool) t) 1 false
|
||||
let bvExpr : BVPred := .getLsbD atom.bvExpr 0
|
||||
let expr := mkApp3 (mkConst ``BVPred.getLsbD) (toExpr 1) atom.expr (toExpr 0)
|
||||
let proof := do
|
||||
|
||||
@@ -209,7 +209,7 @@ where
|
||||
let_expr Eq α discrExpr val := discrExpr | return none
|
||||
let_expr Bool := α | return none
|
||||
let_expr Bool.true := val | return none
|
||||
let some atom ← ReifiedBVExpr.bitVecAtom x | return none
|
||||
let some atom ← ReifiedBVExpr.bitVecAtom x true | return none
|
||||
let some discr ← ReifiedBVLogical.of discrExpr | return none
|
||||
let some lhs ← goOrAtom lhsExpr | return none
|
||||
let some rhs ← goOrAtom rhsExpr | return none
|
||||
@@ -226,7 +226,7 @@ where
|
||||
let res ← go x
|
||||
match res with
|
||||
| some exp => return some exp
|
||||
| none => ReifiedBVExpr.bitVecAtom x
|
||||
| none => ReifiedBVExpr.bitVecAtom x false
|
||||
|
||||
shiftConstLikeReflection (distance : Nat) (innerExpr : Expr) (shiftOp : Nat → BVUnOp)
|
||||
(shiftOpName : Name) (congrThm : Name) :
|
||||
@@ -316,7 +316,7 @@ where
|
||||
return mkApp4 congrProof (toExpr inner.width) innerExpr innerEval innerProof
|
||||
|
||||
goBvLit (x : Expr) : M (Option ReifiedBVExpr) := do
|
||||
let some ⟨_, bvVal⟩ ← getBitVecValue? x | return ← ReifiedBVExpr.bitVecAtom x
|
||||
let some ⟨_, bvVal⟩ ← getBitVecValue? x | return ← ReifiedBVExpr.bitVecAtom x false
|
||||
ReifiedBVExpr.mkBVConst bvVal
|
||||
|
||||
/--
|
||||
|
||||
@@ -263,19 +263,26 @@ private def getOptRotation (stx : Syntax) : Nat :=
|
||||
@[builtin_tactic Parser.Tactic.allGoals] def evalAllGoals : Tactic := fun stx => do
|
||||
let mvarIds ← getGoals
|
||||
let mut mvarIdsNew := #[]
|
||||
let mut abort := false
|
||||
let mut mctxSaved ← getMCtx
|
||||
for mvarId in mvarIds do
|
||||
unless (← mvarId.isAssigned) do
|
||||
setGoals [mvarId]
|
||||
mvarIdsNew ← Tactic.tryCatch
|
||||
abort ← Tactic.tryCatch
|
||||
(do
|
||||
evalTactic stx[1]
|
||||
return mvarIdsNew ++ (← getUnsolvedGoals))
|
||||
pure abort)
|
||||
(fun ex => do
|
||||
if (← read).recover then
|
||||
logException ex
|
||||
return mvarIdsNew.push mvarId
|
||||
pure true
|
||||
else
|
||||
throw ex)
|
||||
mvarIdsNew := mvarIdsNew ++ (← getUnsolvedGoals)
|
||||
if abort then
|
||||
setMCtx mctxSaved
|
||||
mvarIds.forM fun mvarId => unless (← mvarId.isAssigned) do admitGoal mvarId
|
||||
throwAbortTactic
|
||||
setGoals mvarIdsNew.toList
|
||||
|
||||
@[builtin_tactic Parser.Tactic.anyGoals] def evalAnyGoals : Tactic := fun stx => do
|
||||
|
||||
@@ -200,7 +200,7 @@ where
|
||||
if explicit then
|
||||
let i := if i > 0 then i - 1 else i + xs.size
|
||||
if i < 0 || i ≥ xs.size then
|
||||
throwError "invalid '{tacticName}' tactic, application has {xs.size} arguments but the index is out of bounds"
|
||||
throwError "invalid '{tacticName}' tactic, application has {xs.size} argument(s) but the index is out of bounds"
|
||||
let idx := i.natAbs
|
||||
return (mkAppN f xs[0:idx], xs[idx:])
|
||||
else
|
||||
@@ -217,7 +217,7 @@ where
|
||||
explicitIdxs := explicitIdxs.push k
|
||||
let i := if i > 0 then i - 1 else i + explicitIdxs.size
|
||||
if i < 0 || i ≥ explicitIdxs.size then
|
||||
throwError "invalid '{tacticName}' tactic, application has {xs.size} explicit argument(s) but the index is out of bounds"
|
||||
throwError "invalid '{tacticName}' tactic, application has {explicitIdxs.size} explicit argument(s) but the index is out of bounds"
|
||||
let idx := explicitIdxs[i.natAbs]!
|
||||
return (mkAppN f xs[0:idx], xs[idx:])
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ theorem go_denote_eq (aig : AIG BVBit) (expr : BVExpr w) (assign : Assignment) :
|
||||
simp [go, hidx, denote_blastVar]
|
||||
| zeroExtend v inner ih =>
|
||||
simp only [go, denote_blastZeroExtend, ih, dite_eq_ite, Bool.if_false_right,
|
||||
eval_zeroExtend, BitVec.getLsbD_setWidth, hidx, decide_True, Bool.true_and,
|
||||
eval_zeroExtend, BitVec.getLsbD_setWidth, hidx, decide_true, Bool.true_and,
|
||||
Bool.and_iff_right_iff_imp, decide_eq_true_eq]
|
||||
apply BitVec.lt_of_getLsbD
|
||||
| append lhs rhs lih rih =>
|
||||
@@ -78,10 +78,10 @@ theorem go_denote_eq (aig : AIG BVBit) (expr : BVExpr w) (assign : Assignment) :
|
||||
BitVec.getLsbD_append]
|
||||
split
|
||||
· next hsplit =>
|
||||
simp only [hsplit, decide_True, cond_true]
|
||||
simp only [hsplit, decide_true, cond_true]
|
||||
rw [rih]
|
||||
· next hsplit =>
|
||||
simp only [hsplit, decide_False, cond_false]
|
||||
simp only [hsplit, decide_false, cond_false]
|
||||
rw [go_denote_mem_prefix, lih]
|
||||
| replicate n expr ih => simp [go, ih, hidx]
|
||||
| signExtend v inner ih =>
|
||||
@@ -97,7 +97,7 @@ theorem go_denote_eq (aig : AIG BVBit) (expr : BVExpr w) (assign : Assignment) :
|
||||
simp only [eval_signExtend]
|
||||
rw [BitVec.signExtend_eq_not_setWidth_not_of_msb_false]
|
||||
· simp only [denote_blastZeroExtend, ih, dite_eq_ite, Bool.if_false_right,
|
||||
BitVec.getLsbD_setWidth, hidx, decide_True, Bool.true_and, Bool.and_iff_right_iff_imp,
|
||||
BitVec.getLsbD_setWidth, hidx, decide_true, Bool.true_and, Bool.and_iff_right_iff_imp,
|
||||
decide_eq_true_eq]
|
||||
apply BitVec.lt_of_getLsbD
|
||||
· subst heq
|
||||
@@ -108,7 +108,7 @@ theorem go_denote_eq (aig : AIG BVBit) (expr : BVExpr w) (assign : Assignment) :
|
||||
rw [denote_blastSignExtend]
|
||||
simp only [eval_signExtend]
|
||||
rw [BitVec.getLsbD_signExtend]
|
||||
· simp only [hidx, decide_True, Bool.true_and]
|
||||
· simp only [hidx, decide_true, Bool.true_and]
|
||||
split
|
||||
· rw [ih]
|
||||
· rw [BitVec.msb_eq_getLsbD_last]
|
||||
@@ -116,7 +116,7 @@ theorem go_denote_eq (aig : AIG BVBit) (expr : BVExpr w) (assign : Assignment) :
|
||||
· dsimp only; omega
|
||||
| @extract w start len inner ih =>
|
||||
simp only [go, denote_blastExtract, Bool.if_false_right, eval_extract,
|
||||
BitVec.getLsbD_extractLsb', hidx, decide_True, Bool.true_and]
|
||||
BitVec.getLsbD_extractLsb', hidx, decide_true, Bool.true_and]
|
||||
split
|
||||
· next hsplit =>
|
||||
rw [ih]
|
||||
|
||||
@@ -39,7 +39,7 @@ theorem denote_blastNeg (aig : AIG α) (value : BitVec w) (target : RefVec aig w
|
||||
rw [denote_blastAdd]
|
||||
· intro idx hidx
|
||||
rw [AIG.LawfulVecOperator.denote_mem_prefix (f := blastConst)]
|
||||
· simp only [RefVec.get_cast, Ref.gate_cast, BitVec.getLsbD_not, hidx, decide_True,
|
||||
· simp only [RefVec.get_cast, Ref.gate_cast, BitVec.getLsbD_not, hidx, decide_true,
|
||||
Bool.true_and]
|
||||
rw [denote_blastNot, htarget]
|
||||
· simp [Ref.hgate]
|
||||
|
||||
@@ -210,7 +210,7 @@ theorem twoPowShift_eq (aig : AIG α) (target : TwoPowShiftTarget aig w) (lhs :
|
||||
omega
|
||||
· rw [hleft]
|
||||
simp only [BitVec.shiftLeft_eq', BitVec.toNat_twoPow, hmod, BitVec.getLsbD_shiftLeft, hidx,
|
||||
decide_True, Bool.true_and, Bool.iff_and_self, Bool.not_eq_true', decide_eq_false_iff_not,
|
||||
decide_true, Bool.true_and, Bool.iff_and_self, Bool.not_eq_true', decide_eq_false_iff_not,
|
||||
Nat.not_lt]
|
||||
omega
|
||||
· next hif1 =>
|
||||
|
||||
@@ -42,7 +42,7 @@ theorem mkUlt_denote_eq (aig : AIG α) (lhs rhs : BitVec w) (input : BinaryRefVe
|
||||
· dsimp only
|
||||
intro idx hidx
|
||||
rw [AIG.LawfulOperator.denote_mem_prefix (f := AIG.mkConstCached)]
|
||||
· simp only [RefVec.get_cast, Ref.gate_cast, BitVec.getLsbD_not, hidx, decide_True,
|
||||
· simp only [RefVec.get_cast, Ref.gate_cast, BitVec.getLsbD_not, hidx, decide_true,
|
||||
Bool.true_and]
|
||||
rw [BVExpr.bitblast.denote_blastNot]
|
||||
congr 1
|
||||
|
||||
@@ -306,7 +306,7 @@ theorem sat_of_insertRat {n : Nat} (f : DefaultFormula n)
|
||||
simp +decide only [hasAssignment, hasPosAssignment, heq]
|
||||
have p_entails_i := hf.2.2 i false hasNegAssignment_fi p pf
|
||||
simp only [(· ⊨ ·)] at p_entails_i
|
||||
simp only [p_entails_i, decide_True]
|
||||
simp only [p_entails_i, decide_true]
|
||||
· next heq =>
|
||||
exfalso
|
||||
rw [heq] at h3
|
||||
|
||||
@@ -171,7 +171,7 @@ theorem sat_of_insertRup {n : Nat} (f : DefaultFormula n) (f_readyForRupAdd : Re
|
||||
decide
|
||||
have p_entails_i := (assignmentsInvariant_of_strongAssignmentsInvariant f f_readyForRupAdd.2).2 i false hasNegAssignment_fi p pf
|
||||
simp only [(· ⊨ ·)] at p_entails_i
|
||||
simp only [p_entails_i, decide_True]
|
||||
simp only [p_entails_i, decide_true]
|
||||
· next heq =>
|
||||
exfalso
|
||||
rw [heq] at h3
|
||||
@@ -424,7 +424,7 @@ theorem reduce_fold_fn_preserves_induction_motive {c_arr : Array (Literal (PosFi
|
||||
· simp only [(· ⊨ ·), i_eq_idx, c_arr_idx_eq_false] at p_entails_c_arr_i
|
||||
simp only [(· ⊨ ·), Bool.not_eq_true] at p_entails_assignment
|
||||
specialize p_entails_assignment c_arr[idx.1].1
|
||||
simp +decide only [p_entails_c_arr_i, decide_True, heq] at p_entails_assignment
|
||||
simp +decide only [p_entails_c_arr_i, decide_true, heq] at p_entails_assignment
|
||||
· next h =>
|
||||
exact Or.inr h
|
||||
· exact Or.inr ih1
|
||||
@@ -443,7 +443,7 @@ theorem reduce_fold_fn_preserves_induction_motive {c_arr : Array (Literal (PosFi
|
||||
· simp only [(· ⊨ ·), i_eq_idx, c_arr_idx_eq_false] at p_entails_c_arr_i
|
||||
simp only [(· ⊨ ·), Bool.not_eq_true] at p_entails_assignment
|
||||
specialize p_entails_assignment c_arr[idx.1].1
|
||||
simp +decide only [p_entails_c_arr_i, decide_True, heq] at p_entails_assignment
|
||||
simp +decide only [p_entails_c_arr_i, decide_true, heq] at p_entails_assignment
|
||||
· next h =>
|
||||
exact Or.inr h
|
||||
· exact Or.inr ih1
|
||||
@@ -519,7 +519,7 @@ theorem reduce_fold_fn_preserves_induction_motive {c_arr : Array (Literal (PosFi
|
||||
· simp only [j_eq_idx, (· ⊨ ·), c_arr_idx_eq_false] at p_entails_c_arr_j
|
||||
simp only [(· ⊨ ·), Bool.not_eq_true] at hp
|
||||
specialize hp c_arr[idx.1].1
|
||||
simp +decide only [p_entails_c_arr_j, decide_True, heq] at hp
|
||||
simp +decide only [p_entails_c_arr_j, decide_true, heq] at hp
|
||||
· next heq =>
|
||||
split at h
|
||||
· simp at h
|
||||
@@ -534,7 +534,7 @@ theorem reduce_fold_fn_preserves_induction_motive {c_arr : Array (Literal (PosFi
|
||||
· simp only [j_eq_idx, (· ⊨ ·), c_arr_idx_eq_true] at p_entails_c_arr_j
|
||||
simp only [(· ⊨ ·), Bool.not_eq_true] at hp
|
||||
specialize hp c_arr[idx.1].1
|
||||
simp +decide only [p_entails_c_arr_j, decide_True, heq] at hp
|
||||
simp +decide only [p_entails_c_arr_j, decide_true, heq] at hp
|
||||
· simp at h
|
||||
· simp at h
|
||||
· simp at h
|
||||
@@ -683,8 +683,8 @@ theorem confirmRupHint_preserves_motive {n : Nat} (f : DefaultFormula n) (rupHin
|
||||
Array.get_eq_getElem, l_eq_i, Array.getElem_modify_self (addAssignment b), decidableGetElem?]
|
||||
simp only [getElem!, i_in_bounds, dite_true, Array.get_eq_getElem, decidableGetElem?] at pacc
|
||||
by_cases pi : p i
|
||||
· simp only [pi, decide_False]
|
||||
simp only [hasAssignment, pi, decide_False, ite_false] at pacc
|
||||
· simp only [pi, decide_false]
|
||||
simp only [hasAssignment, pi, decide_false, ite_false] at pacc
|
||||
by_cases hb : b
|
||||
· simp only [hasAssignment, ↓reduceIte, addAssignment]
|
||||
simp only [hb]
|
||||
@@ -694,8 +694,8 @@ theorem confirmRupHint_preserves_motive {n : Nat} (f : DefaultFormula n) (rupHin
|
||||
simp only [Bool.not_eq_true] at hb
|
||||
simp [(· ⊨ ·), hb, Subtype.ext l_eq_i, pi] at plb
|
||||
· simp only [Bool.not_eq_true] at pi
|
||||
simp only [pi, decide_True]
|
||||
simp only [pi, decide_True] at pacc
|
||||
simp only [pi, decide_true]
|
||||
simp only [pi, decide_true] at pacc
|
||||
by_cases hb : b
|
||||
· simp [(· ⊨ ·), hb, Subtype.ext l_eq_i, pi] at plb
|
||||
· simp only [Bool.not_eq_true] at hb
|
||||
|
||||
@@ -120,6 +120,7 @@ theorem BitVec.srem_umod (x y : BitVec w) :
|
||||
|
||||
attribute [bv_normalize] Bool.cond_eq_if
|
||||
attribute [bv_normalize] BitVec.abs_eq
|
||||
attribute [bv_normalize] BitVec.twoPow_eq
|
||||
|
||||
end Reduce
|
||||
|
||||
|
||||
@@ -1651,7 +1651,7 @@ static inline uint8_t lean_uint8_dec_lt(uint8_t a1, uint8_t a2) { return a1 < a2
|
||||
static inline uint8_t lean_uint8_dec_le(uint8_t a1, uint8_t a2) { return a1 <= a2; }
|
||||
|
||||
|
||||
/* Unit8 -> other */
|
||||
/* UInt8 -> other */
|
||||
static inline uint16_t lean_uint8_to_uint16(uint8_t a) { return ((uint16_t)a); }
|
||||
static inline uint32_t lean_uint8_to_uint32(uint8_t a) { return ((uint32_t)a); }
|
||||
static inline uint64_t lean_uint8_to_uint64(uint8_t a) { return ((uint64_t)a); }
|
||||
@@ -1686,7 +1686,7 @@ static inline uint8_t lean_uint16_dec_eq(uint16_t a1, uint16_t a2) { return a1 =
|
||||
static inline uint8_t lean_uint16_dec_lt(uint16_t a1, uint16_t a2) { return a1 < a2; }
|
||||
static inline uint8_t lean_uint16_dec_le(uint16_t a1, uint16_t a2) { return a1 <= a2; }
|
||||
|
||||
/*uint16 -> other */
|
||||
/* UInt16 -> other */
|
||||
static inline uint8_t lean_uint16_to_uint8(uint16_t a) { return ((uint8_t)a); }
|
||||
static inline uint32_t lean_uint16_to_uint32(uint16_t a) { return ((uint32_t)a); }
|
||||
static inline uint64_t lean_uint16_to_uint64(uint16_t a) { return ((uint64_t)a); }
|
||||
@@ -1721,7 +1721,7 @@ static inline uint8_t lean_uint32_dec_eq(uint32_t a1, uint32_t a2) { return a1 =
|
||||
static inline uint8_t lean_uint32_dec_lt(uint32_t a1, uint32_t a2) { return a1 < a2; }
|
||||
static inline uint8_t lean_uint32_dec_le(uint32_t a1, uint32_t a2) { return a1 <= a2; }
|
||||
|
||||
/* uint32 -> other */
|
||||
/* UInt32 -> other */
|
||||
static inline uint8_t lean_uint32_to_uint8(uint32_t a) { return ((uint8_t)a); }
|
||||
static inline uint16_t lean_uint32_to_uint16(uint32_t a) { return ((uint16_t)a); }
|
||||
static inline uint64_t lean_uint32_to_uint64(uint32_t a) { return ((uint64_t)a); }
|
||||
@@ -1759,7 +1759,7 @@ static inline uint8_t lean_uint64_dec_le(uint64_t a1, uint64_t a2) { return a1 <
|
||||
LEAN_EXPORT uint64_t lean_uint64_mix_hash(uint64_t a1, uint64_t a2);
|
||||
|
||||
|
||||
/* uint64 -> other */
|
||||
/* UInt64 -> other */
|
||||
static inline uint8_t lean_uint64_to_uint8(uint64_t a) { return ((uint8_t)a); }
|
||||
static inline uint16_t lean_uint64_to_uint16(uint64_t a) { return ((uint16_t)a); }
|
||||
static inline uint32_t lean_uint64_to_uint32(uint64_t a) { return ((uint32_t)a); }
|
||||
@@ -1826,6 +1826,18 @@ static inline uint8_t lean_int8_of_int(b_lean_obj_arg a) {
|
||||
return (uint8_t)res;
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_of_nat(b_lean_obj_arg a) {
|
||||
int8_t res;
|
||||
|
||||
if (lean_is_scalar(a)) {
|
||||
res = (int8_t)lean_unbox(a);
|
||||
} else {
|
||||
res = lean_int8_of_big_int(a);
|
||||
}
|
||||
|
||||
return (uint8_t)res;
|
||||
}
|
||||
|
||||
static inline lean_obj_res lean_int8_to_int(uint8_t a) {
|
||||
int8_t arg = (int8_t)a;
|
||||
return lean_int64_to_int((int64_t)arg);
|
||||
@@ -1838,73 +1850,73 @@ static inline uint8_t lean_int8_neg(uint8_t a) {
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_add(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (int8_t)a2;
|
||||
|
||||
return (uint8_t)(lhs + rhs);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_sub(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (int8_t)a2;
|
||||
|
||||
return (uint8_t)(lhs - rhs);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_mul(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (int8_t)a2;
|
||||
|
||||
return (uint8_t)(lhs * rhs);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_div(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (int8_t)a2;
|
||||
|
||||
return (uint8_t)(rhs == 0 ? 0 : lhs / rhs);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_mod(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (int8_t)a2;
|
||||
|
||||
return (uint8_t)(rhs == 0 ? 0 : lhs % rhs);
|
||||
return (uint8_t)(rhs == 0 ? lhs : lhs % rhs);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_land(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (int8_t)a2;
|
||||
|
||||
return (uint8_t)(lhs & rhs);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_lor(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (int8_t)a2;
|
||||
|
||||
return (uint8_t)(lhs | rhs);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_xor(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (int8_t)a2;
|
||||
|
||||
return (uint8_t)(lhs ^ rhs);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_shift_right(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (((int8_t)a2 % 8) + 8) % 8; // this is smod 8
|
||||
|
||||
return (uint8_t)(lhs >> (rhs % 8));
|
||||
return (uint8_t)(lhs >> rhs);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_shift_left(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (((int8_t)a2 % 8) + 8) % 8; // this is smod 8
|
||||
|
||||
return (uint8_t)(lhs << (rhs % 8));
|
||||
return (uint8_t)(lhs << rhs);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_complement(uint8_t a) {
|
||||
@@ -1914,26 +1926,591 @@ static inline uint8_t lean_int8_complement(uint8_t a) {
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_dec_eq(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (int8_t)a2;
|
||||
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_dec_lt(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (int8_t)a2;
|
||||
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int8_dec_le(uint8_t a1, uint8_t a2) {
|
||||
int8_t lhs = (int8_t) a1;
|
||||
int8_t rhs = (int8_t) a2;
|
||||
int8_t lhs = (int8_t)a1;
|
||||
int8_t rhs = (int8_t)a2;
|
||||
|
||||
return lhs <= rhs;
|
||||
}
|
||||
|
||||
/* Int8 -> other */
|
||||
static inline uint16_t lean_int8_to_int16(uint8_t a) { return (uint16_t)(int16_t)(int8_t)a; }
|
||||
static inline uint32_t lean_int8_to_int32(uint8_t a) { return (uint32_t)(int32_t)(int8_t)a; }
|
||||
static inline uint64_t lean_int8_to_int64(uint8_t a) { return (uint64_t)(int64_t)(int8_t)a; }
|
||||
|
||||
|
||||
/* Int16 */
|
||||
LEAN_EXPORT int16_t lean_int16_of_big_int(b_lean_obj_arg a);
|
||||
static inline uint16_t lean_int16_of_int(b_lean_obj_arg a) {
|
||||
int16_t res;
|
||||
|
||||
if (lean_is_scalar(a)) {
|
||||
res = (int16_t)lean_scalar_to_int64(a);
|
||||
} else {
|
||||
res = lean_int16_of_big_int(a);
|
||||
}
|
||||
|
||||
return (uint16_t)res;
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_of_nat(b_lean_obj_arg a) {
|
||||
int16_t res;
|
||||
|
||||
if (lean_is_scalar(a)) {
|
||||
res = (int16_t)lean_unbox(a);
|
||||
} else {
|
||||
res = lean_int16_of_big_int(a);
|
||||
}
|
||||
|
||||
return (uint16_t)res;
|
||||
}
|
||||
|
||||
static inline lean_obj_res lean_int16_to_int(uint16_t a) {
|
||||
int16_t arg = (int16_t)a;
|
||||
return lean_int64_to_int((int64_t)arg);
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_neg(uint16_t a) {
|
||||
int16_t arg = (int16_t)a;
|
||||
|
||||
return (uint16_t)(-arg);
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_add(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (int16_t)a2;
|
||||
|
||||
return (uint16_t)(lhs + rhs);
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_sub(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (int16_t)a2;
|
||||
|
||||
return (uint16_t)(lhs - rhs);
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_mul(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (int16_t)a2;
|
||||
|
||||
return (uint16_t)(lhs * rhs);
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_div(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (int16_t)a2;
|
||||
|
||||
return (uint16_t)(rhs == 0 ? 0 : lhs / rhs);
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_mod(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (int16_t)a2;
|
||||
|
||||
return (uint16_t)(rhs == 0 ? lhs : lhs % rhs);
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_land(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (int16_t)a2;
|
||||
|
||||
return (uint16_t)(lhs & rhs);
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_lor(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (int16_t)a2;
|
||||
|
||||
return (uint16_t)(lhs | rhs);
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_xor(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (int16_t)a2;
|
||||
|
||||
return (uint16_t)(lhs ^ rhs);
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_shift_right(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (((int16_t)a2 % 16) + 16) % 16; // this is smod 16
|
||||
|
||||
return (uint16_t)(lhs >> rhs);
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_shift_left(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (((int16_t)a2 % 16) + 16) % 16; // this is smod 16
|
||||
|
||||
return (uint16_t)(lhs << rhs);
|
||||
}
|
||||
|
||||
static inline uint16_t lean_int16_complement(uint16_t a) {
|
||||
int16_t arg = (int16_t)a;
|
||||
|
||||
return (uint16_t)(~arg);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int16_dec_eq(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (int16_t)a2;
|
||||
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int16_dec_lt(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (int16_t)a2;
|
||||
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int16_dec_le(uint16_t a1, uint16_t a2) {
|
||||
int16_t lhs = (int16_t)a1;
|
||||
int16_t rhs = (int16_t)a2;
|
||||
|
||||
return lhs <= rhs;
|
||||
}
|
||||
|
||||
/* Int16 -> other */
|
||||
static inline uint8_t lean_int16_to_int8(uint16_t a) { return (uint8_t)(int8_t)(int16_t)a; }
|
||||
static inline uint32_t lean_int16_to_int32(uint16_t a) { return (uint32_t)(int32_t)(int16_t)a; }
|
||||
static inline uint64_t lean_int16_to_int64(uint16_t a) { return (uint64_t)(int64_t)(int16_t)a; }
|
||||
|
||||
/* Int32 */
|
||||
LEAN_EXPORT int32_t lean_int32_of_big_int(b_lean_obj_arg a);
|
||||
static inline uint32_t lean_int32_of_int(b_lean_obj_arg a) {
|
||||
int32_t res;
|
||||
|
||||
if (lean_is_scalar(a)) {
|
||||
res = (int32_t)lean_scalar_to_int64(a);
|
||||
} else {
|
||||
res = lean_int32_of_big_int(a);
|
||||
}
|
||||
|
||||
return (uint32_t)res;
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_of_nat(b_lean_obj_arg a) {
|
||||
int32_t res;
|
||||
|
||||
if (lean_is_scalar(a)) {
|
||||
res = (int32_t)lean_unbox(a);
|
||||
} else {
|
||||
res = lean_int32_of_big_int(a);
|
||||
}
|
||||
|
||||
return (uint32_t)res;
|
||||
}
|
||||
|
||||
static inline lean_obj_res lean_int32_to_int(uint32_t a) {
|
||||
int32_t arg = (int32_t)a;
|
||||
return lean_int64_to_int((int64_t)arg);
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_neg(uint32_t a) {
|
||||
int32_t arg = (int32_t)a;
|
||||
|
||||
return (uint32_t)(-arg);
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_add(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (int32_t)a2;
|
||||
|
||||
return (uint32_t)(lhs + rhs);
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_sub(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (int32_t)a2;
|
||||
|
||||
return (uint32_t)(lhs - rhs);
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_mul(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (int32_t)a2;
|
||||
|
||||
return (uint32_t)(lhs * rhs);
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_div(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (int32_t)a2;
|
||||
|
||||
return (uint32_t)(rhs == 0 ? 0 : lhs / rhs);
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_mod(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (int32_t)a2;
|
||||
|
||||
return (uint32_t)(rhs == 0 ? lhs : lhs % rhs);
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_land(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (int32_t)a2;
|
||||
|
||||
return (uint32_t)(lhs & rhs);
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_lor(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (int32_t)a2;
|
||||
|
||||
return (uint32_t)(lhs | rhs);
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_xor(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (int32_t)a2;
|
||||
|
||||
return (uint32_t)(lhs ^ rhs);
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_shift_right(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (((int32_t)a2 % 32) + 32) % 32; // this is smod 32
|
||||
|
||||
return (uint32_t)(lhs >> rhs);
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_shift_left(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (((int32_t)a2 % 32) + 32) % 32; // this is smod 32
|
||||
|
||||
return (uint32_t)(lhs << rhs);
|
||||
}
|
||||
|
||||
static inline uint32_t lean_int32_complement(uint32_t a) {
|
||||
int32_t arg = (int32_t)a;
|
||||
|
||||
return (uint32_t)(~arg);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int32_dec_eq(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (int32_t)a2;
|
||||
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int32_dec_lt(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (int32_t)a2;
|
||||
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int32_dec_le(uint32_t a1, uint32_t a2) {
|
||||
int32_t lhs = (int32_t)a1;
|
||||
int32_t rhs = (int32_t)a2;
|
||||
|
||||
return lhs <= rhs;
|
||||
}
|
||||
|
||||
/* Int32 -> other */
|
||||
static inline uint8_t lean_int32_to_int8(uint32_t a) { return (uint8_t)(int8_t)(int32_t)a; }
|
||||
static inline uint16_t lean_int32_to_int16(uint32_t a) { return (uint16_t)(int16_t)(int32_t)a; }
|
||||
static inline uint64_t lean_int32_to_int64(uint32_t a) { return (uint64_t)(int64_t)(int32_t)a; }
|
||||
static inline size_t lean_int32_to_isize(uint32_t a) { return (size_t)(ptrdiff_t)(int32_t)a; }
|
||||
|
||||
/* Int64 */
|
||||
LEAN_EXPORT int64_t lean_int64_of_big_int(b_lean_obj_arg a);
|
||||
static inline uint64_t lean_int64_of_int(b_lean_obj_arg a) {
|
||||
int64_t res;
|
||||
|
||||
if (lean_is_scalar(a)) {
|
||||
res = lean_scalar_to_int64(a);
|
||||
} else {
|
||||
res = lean_int64_of_big_int(a);
|
||||
}
|
||||
|
||||
return (uint64_t)res;
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_of_nat(b_lean_obj_arg a) {
|
||||
int64_t res;
|
||||
|
||||
if (lean_is_scalar(a)) {
|
||||
res = (int64_t)lean_unbox(a);
|
||||
} else {
|
||||
res = lean_int64_of_big_int(a);
|
||||
}
|
||||
|
||||
return (uint64_t)res;
|
||||
}
|
||||
|
||||
static inline lean_obj_res lean_int64_to_int_sint(uint64_t a) {
|
||||
int64_t arg = (int64_t)a;
|
||||
return lean_int64_to_int(arg);
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_neg(uint64_t a) {
|
||||
int64_t arg = (int64_t)a;
|
||||
|
||||
return (uint64_t)(-arg);
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_add(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (int64_t)a2;
|
||||
|
||||
return (uint64_t)(lhs + rhs);
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_sub(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (int64_t)a2;
|
||||
|
||||
return (uint64_t)(lhs - rhs);
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_mul(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (int64_t)a2;
|
||||
|
||||
return (uint64_t)(lhs * rhs);
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_div(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (int64_t)a2;
|
||||
|
||||
return (uint64_t)(rhs == 0 ? 0 : lhs / rhs);
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_mod(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (int64_t)a2;
|
||||
|
||||
return (uint64_t)(rhs == 0 ? lhs : lhs % rhs);
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_land(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (int64_t)a2;
|
||||
|
||||
return (uint64_t)(lhs & rhs);
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_lor(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (int64_t)a2;
|
||||
|
||||
return (uint64_t)(lhs | rhs);
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_xor(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (int64_t)a2;
|
||||
|
||||
return (uint64_t)(lhs ^ rhs);
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_shift_right(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (((int64_t)a2 % 64) + 64) % 64; // this is smod 64
|
||||
|
||||
return (uint64_t)(lhs >> rhs);
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_shift_left(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (((int64_t)a2 % 64) + 64) % 64; // this is smod 64
|
||||
|
||||
return (uint64_t)(lhs << rhs);
|
||||
}
|
||||
|
||||
static inline uint64_t lean_int64_complement(uint64_t a) {
|
||||
int64_t arg = (int64_t)a;
|
||||
|
||||
return (uint64_t)(~arg);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int64_dec_eq(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (int64_t)a2;
|
||||
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int64_dec_lt(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (int64_t)a2;
|
||||
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
static inline uint8_t lean_int64_dec_le(uint64_t a1, uint64_t a2) {
|
||||
int64_t lhs = (int64_t)a1;
|
||||
int64_t rhs = (int64_t)a2;
|
||||
|
||||
return lhs <= rhs;
|
||||
}
|
||||
|
||||
/* Int64 -> other */
|
||||
static inline uint8_t lean_int64_to_int8(uint64_t a) { return (uint8_t)(int8_t)(int64_t)a; }
|
||||
static inline uint16_t lean_int64_to_int16(uint64_t a) { return (uint16_t)(int16_t)(int64_t)a; }
|
||||
static inline uint32_t lean_int64_to_int32(uint64_t a) { return (uint32_t)(int32_t)(int64_t)a; }
|
||||
static inline size_t lean_int64_to_isize(uint64_t a) { return (size_t)(ptrdiff_t)(int64_t)a; }
|
||||
|
||||
/* ISize */
|
||||
LEAN_EXPORT ptrdiff_t lean_isize_of_big_int(b_lean_obj_arg a);
|
||||
static inline size_t lean_isize_of_int(b_lean_obj_arg a) {
|
||||
ptrdiff_t res;
|
||||
|
||||
if (lean_is_scalar(a)) {
|
||||
res = (ptrdiff_t)lean_scalar_to_int64(a);
|
||||
} else {
|
||||
res = lean_isize_of_big_int(a);
|
||||
}
|
||||
|
||||
return (size_t)res;
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_of_nat(b_lean_obj_arg a) {
|
||||
ptrdiff_t res;
|
||||
|
||||
if (lean_is_scalar(a)) {
|
||||
res = (ptrdiff_t)lean_unbox(a);
|
||||
} else {
|
||||
res = lean_isize_of_big_int(a);
|
||||
}
|
||||
|
||||
return (size_t)res;
|
||||
}
|
||||
|
||||
static inline lean_obj_res lean_isize_to_int(size_t a) {
|
||||
ptrdiff_t arg = (ptrdiff_t)a;
|
||||
return lean_int64_to_int((int64_t)arg);
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_neg(size_t a) {
|
||||
ptrdiff_t arg = (ptrdiff_t)a;
|
||||
|
||||
return (size_t)(-arg);
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_add(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t rhs = (ptrdiff_t)a2;
|
||||
|
||||
return (size_t)(lhs + rhs);
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_sub(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t rhs = (ptrdiff_t)a2;
|
||||
|
||||
return (size_t)(lhs - rhs);
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_mul(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t rhs = (ptrdiff_t)a2;
|
||||
|
||||
return (size_t)(lhs * rhs);
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_div(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t rhs = (ptrdiff_t)a2;
|
||||
|
||||
return (size_t)(rhs == 0 ? 0 : lhs / rhs);
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_mod(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t rhs = (ptrdiff_t)a2;
|
||||
|
||||
return (size_t)(rhs == 0 ? lhs : lhs % rhs);
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_land(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t rhs = (ptrdiff_t)a2;
|
||||
|
||||
return (size_t)(lhs & rhs);
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_lor(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t rhs = (ptrdiff_t)a2;
|
||||
|
||||
return (size_t)(lhs | rhs);
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_xor(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t rhs = (ptrdiff_t)a2;
|
||||
|
||||
return (size_t)(lhs ^ rhs);
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_shift_right(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t size = sizeof(ptrdiff_t) * 8;
|
||||
ptrdiff_t rhs = (((ptrdiff_t)a2 % size) + size) % size; // this is smod
|
||||
|
||||
return (size_t)(lhs >> rhs);
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_shift_left(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t size = sizeof(ptrdiff_t) * 8;
|
||||
ptrdiff_t rhs = (((ptrdiff_t)a2 % size) + size) % size; // this is smod
|
||||
|
||||
return (size_t)(lhs << rhs);
|
||||
}
|
||||
|
||||
static inline size_t lean_isize_complement(size_t a) {
|
||||
ptrdiff_t arg = (ptrdiff_t)a;
|
||||
|
||||
return (size_t)(~arg);
|
||||
}
|
||||
|
||||
static inline uint8_t lean_isize_dec_eq(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t rhs = (ptrdiff_t)a2;
|
||||
|
||||
return lhs == rhs;
|
||||
}
|
||||
|
||||
static inline uint8_t lean_isize_dec_lt(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t rhs = (ptrdiff_t)a2;
|
||||
|
||||
return lhs < rhs;
|
||||
}
|
||||
|
||||
static inline uint8_t lean_isize_dec_le(size_t a1, size_t a2) {
|
||||
ptrdiff_t lhs = (ptrdiff_t)a1;
|
||||
ptrdiff_t rhs = (ptrdiff_t)a2;
|
||||
|
||||
return lhs <= rhs;
|
||||
}
|
||||
|
||||
/* ISize -> other */
|
||||
static inline uint32_t lean_isize_to_int32(size_t a) { return (uint32_t)(int32_t)(ptrdiff_t)a; }
|
||||
static inline uint64_t lean_isize_to_int64(size_t a) { return (uint64_t)(int64_t)(ptrdiff_t)a; }
|
||||
|
||||
/* Float */
|
||||
|
||||
LEAN_EXPORT lean_obj_res lean_float_to_string(double a);
|
||||
|
||||
@@ -19,7 +19,10 @@ open Lean (Name)
|
||||
|
||||
/-- Compute a topological ordering of the package's transitive dependencies. -/
|
||||
def Package.recComputeDeps (self : Package) : FetchM (Array Package) := do
|
||||
(·.toArray) <$> self.deps.foldlM (init := OrdPackageSet.empty) fun deps dep => do
|
||||
(·.toArray) <$> self.depConfigs.foldlM (init := OrdPackageSet.empty) fun deps cfg => do
|
||||
let some dep ← findPackage? cfg.name
|
||||
| error s!"{self.name}: package not found for dependency '{cfg.name}' \
|
||||
(this is likely a bug in Lake)"
|
||||
return (← fetch <| dep.facet `deps).foldl (·.insert ·) deps |>.insert dep
|
||||
|
||||
/-- The `PackageFacetConfig` for the builtin `depsFacet`. -/
|
||||
|
||||
@@ -36,6 +36,10 @@ fetch functions, but not all fetch functions need build something.
|
||||
abbrev DFetchFn (α : Type u) (β : α → Type v) (m : Type v → Type w) :=
|
||||
(a : α) → m (β a)
|
||||
|
||||
/-- A `DFetchFn` that is not dependently typed. -/
|
||||
abbrev FetchFn (α : Type u) (β : Type v) (m : Type v → Type w) :=
|
||||
α → m β
|
||||
|
||||
/-!
|
||||
In order to nest builds / fetches within one another,
|
||||
we equip the monad `m` with a fetch function of its own.
|
||||
|
||||
@@ -41,12 +41,12 @@ BASIC OPTIONS:
|
||||
--help, -h print help of the program or a command and exit
|
||||
--dir, -d=file use the package configuration in a specific directory
|
||||
--file, -f=file use a specific file for the package configuration
|
||||
--lean=cmd specify the `lean` command used by Lake
|
||||
-K key[=value] set the configuration file option named key
|
||||
--old only rebuild modified modules (ignore transitive deps)
|
||||
--rehash, -H hash all files for traces (do not trust `.hash` files)
|
||||
--update, -U update manifest before building
|
||||
--update, -U update dependencies on load (e.g., before a build)
|
||||
--reconfigure, -R elaborate configuration files instead of using OLeans
|
||||
--keep-toolchain do not update toolchain on workspace update
|
||||
--no-build exit immediately if a build target is not up-to-date
|
||||
--no-cache build packages locally; do not download build caches
|
||||
--try-cache attempt to download build caches for supported packages
|
||||
|
||||
@@ -5,6 +5,7 @@ Authors: Gabriel Ebner, Sebastian Ullrich, Mac Malone
|
||||
-/
|
||||
import Lake.Util.Git
|
||||
import Lake.Util.Sugar
|
||||
import Lake.Util.Version
|
||||
import Lake.Config.Lang
|
||||
import Lake.Config.Package
|
||||
import Lake.Config.Workspace
|
||||
@@ -18,9 +19,6 @@ open Lean (Name)
|
||||
/-- The default module of an executable in `std` package. -/
|
||||
def defaultExeRoot : Name := `Main
|
||||
|
||||
/-- `elan` toolchain file name -/
|
||||
def toolchainFileName : FilePath := "lean-toolchain"
|
||||
|
||||
def gitignoreContents :=
|
||||
s!"/{defaultLakeDir}
|
||||
"
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Lake
|
||||
/-! ## General options for top-level `lake` -/
|
||||
|
||||
structure LakeOptions where
|
||||
args : List String := []
|
||||
rootDir : FilePath := "."
|
||||
configFile : FilePath := defaultConfigFile
|
||||
elanInstall? : Option ElanInstall := none
|
||||
@@ -36,6 +37,7 @@ structure LakeOptions where
|
||||
wantsHelp : Bool := false
|
||||
verbosity : Verbosity := .normal
|
||||
updateDeps : Bool := false
|
||||
updateToolchain : Bool := true
|
||||
reconfigure : Bool := false
|
||||
oldMode : Bool := false
|
||||
trustHash : Bool := true
|
||||
@@ -72,12 +74,15 @@ def LakeOptions.computeEnv (opts : LakeOptions) : EIO CliError Lake.Env := do
|
||||
/-- Make a `LoadConfig` from a `LakeOptions`. -/
|
||||
def LakeOptions.mkLoadConfig (opts : LakeOptions) : EIO CliError LoadConfig :=
|
||||
return {
|
||||
lakeArgs? := opts.args.toArray
|
||||
lakeEnv := ← opts.computeEnv
|
||||
wsDir := opts.rootDir
|
||||
relConfigFile := opts.configFile
|
||||
lakeOpts := opts.configOpts
|
||||
leanOpts := Lean.Options.empty
|
||||
reconfigure := opts.reconfigure
|
||||
updateDeps := opts.updateDeps
|
||||
updateToolchain := opts.updateToolchain
|
||||
}
|
||||
|
||||
/-- Make a `BuildConfig` from a `LakeOptions`. -/
|
||||
@@ -101,7 +106,7 @@ abbrev CliM := ArgsT CliStateM
|
||||
|
||||
def CliM.run (self : CliM α) (args : List String) : BaseIO ExitCode := do
|
||||
let (elanInstall?, leanInstall?, lakeInstall?) ← findInstall?
|
||||
let main := self.run' args |>.run' {elanInstall?, leanInstall?, lakeInstall?}
|
||||
let main := self.run' args |>.run' {args, elanInstall?, leanInstall?, lakeInstall?}
|
||||
let main := main.run >>= fun | .ok a => pure a | .error e => error e.toString
|
||||
main.run
|
||||
|
||||
@@ -111,6 +116,12 @@ def CliM.run (self : CliM α) (args : List String) : BaseIO ExitCode := do
|
||||
|
||||
instance (priority := low) : MonadLift LogIO CliStateM := ⟨CliStateM.runLogIO⟩
|
||||
|
||||
@[inline] def CliStateM.runLoggerIO (x : LoggerIO α) : CliStateM α := do
|
||||
let opts ← get
|
||||
MainM.runLoggerIO x opts.outLv opts.ansiMode
|
||||
|
||||
instance (priority := low) : MonadLift LoggerIO CliStateM := ⟨CliStateM.runLoggerIO⟩
|
||||
|
||||
/-! ## Argument Parsing -/
|
||||
|
||||
def takeArg (arg : String) : CliM String := do
|
||||
@@ -141,10 +152,6 @@ def noArgsRem (act : CliStateM α) : CliM α := do
|
||||
def getWantsHelp : CliStateM Bool :=
|
||||
(·.wantsHelp) <$> get
|
||||
|
||||
def setLean (lean : String) : CliStateM PUnit := do
|
||||
let leanInstall? ← findLeanCmdInstall? lean
|
||||
modify ({· with leanInstall?})
|
||||
|
||||
def setConfigOpt (kvPair : String) : CliM PUnit :=
|
||||
let pos := kvPair.posOf '='
|
||||
let (key, val) :=
|
||||
@@ -171,6 +178,7 @@ def lakeLongOption : (opt : String) → CliM PUnit
|
||||
| "--quiet" => modifyThe LakeOptions ({· with verbosity := .quiet})
|
||||
| "--verbose" => modifyThe LakeOptions ({· with verbosity := .verbose})
|
||||
| "--update" => modifyThe LakeOptions ({· with updateDeps := true})
|
||||
| "--keep-toolchain" => modifyThe LakeOptions ({· with updateToolchain := false})
|
||||
| "--reconfigure" => modifyThe LakeOptions ({· with reconfigure := true})
|
||||
| "--old" => modifyThe LakeOptions ({· with oldMode := true})
|
||||
| "--no-build" => modifyThe LakeOptions ({· with noBuild := true})
|
||||
@@ -193,7 +201,6 @@ def lakeLongOption : (opt : String) → CliM PUnit
|
||||
| "--file" => do
|
||||
let configFile ← takeOptArg "--file" "path"
|
||||
modifyThe LakeOptions ({· with configFile})
|
||||
| "--lean" => do setLean <| ← takeOptArg "--lean" "path or command"
|
||||
| "--help" => modifyThe LakeOptions ({· with wantsHelp := true})
|
||||
| "--" => do
|
||||
let subArgs ← takeArgs
|
||||
@@ -331,7 +338,7 @@ protected def build : CliM PUnit := do
|
||||
processOptions lakeOption
|
||||
let opts ← getThe LakeOptions
|
||||
let config ← mkLoadConfig opts
|
||||
let ws ← loadWorkspace config opts.updateDeps
|
||||
let ws ← loadWorkspace config
|
||||
let targetSpecs ← takeArgs
|
||||
let specs ← parseTargetSpecs ws targetSpecs
|
||||
let buildConfig := mkBuildConfig opts (out := .stdout)
|
||||
@@ -350,7 +357,7 @@ protected def resolveDeps : CliM PUnit := do
|
||||
let opts ← getThe LakeOptions
|
||||
let config ← mkLoadConfig opts
|
||||
noArgsRem do
|
||||
discard <| loadWorkspace config opts.updateDeps
|
||||
discard <| loadWorkspace config
|
||||
|
||||
protected def update : CliM PUnit := do
|
||||
processOptions lakeOption
|
||||
|
||||
@@ -38,7 +38,7 @@ def setupFile
|
||||
IO.eprintln s!"Invalid Lake configuration. Please restart the server after fixing the Lake configuration file."
|
||||
exit 1
|
||||
let outLv := buildConfig.verbosity.minLogLv
|
||||
let ws ← MainM.runLogIO (minLv := outLv) (ansiMode := .noAnsi) do
|
||||
let ws ← MainM.runLoggerIO (minLv := outLv) (ansiMode := .noAnsi) do
|
||||
loadWorkspace loadConfig
|
||||
let imports := imports.foldl (init := #[]) fun imps imp =>
|
||||
if let some mod := ws.findModule? imp.toName then imps.push mod else imps
|
||||
@@ -71,7 +71,7 @@ with the given additional `args`.
|
||||
-/
|
||||
def serve (config : LoadConfig) (args : Array String) : IO UInt32 := do
|
||||
let (extraEnv, moreServerArgs) ← do
|
||||
let (ws?, log) ← (loadWorkspace config).run?
|
||||
let (ws?, log) ← (loadWorkspace config).captureLog
|
||||
log.replay (logger := MonadLog.stderr)
|
||||
if let some ws := ws? then
|
||||
let ctx := mkLakeContext ws
|
||||
|
||||
@@ -63,7 +63,7 @@ def compute
|
||||
lake, lean, elan?,
|
||||
pkgUrlMap := ← computePkgUrlMap
|
||||
reservoirApiUrl := ← getUrlD "RESERVOIR_API_URL" s!"{reservoirBaseUrl}/v1"
|
||||
noCache := (noCache <|> (← IO.getEnv "LAKE_NO_CACHE").bind toBool?).getD false
|
||||
noCache := (noCache <|> (← IO.getEnv "LAKE_NO_CACHE").bind envToBool?).getD false
|
||||
githashOverride := (← IO.getEnv "LEAN_GITHASH").getD ""
|
||||
initToolchain := (← IO.getEnv "ELAN_TOOLCHAIN").getD ""
|
||||
initLeanPath := ← getSearchPath "LEAN_PATH",
|
||||
@@ -72,10 +72,6 @@ def compute
|
||||
initPath := ← getSearchPath "PATH"
|
||||
}
|
||||
where
|
||||
toBool? (o : String) : Option Bool :=
|
||||
if ["y", "yes", "t", "true", "on", "1"].contains o.toLower then true
|
||||
else if ["n", "no", "f", "false", "off", "0"].contains o.toLower then false
|
||||
else none
|
||||
computePkgUrlMap := do
|
||||
let some urlMapStr ← IO.getEnv "LAKE_PKG_URL_MAP" | return {}
|
||||
match Json.parse urlMapStr |>.bind fromJson? with
|
||||
@@ -144,14 +140,29 @@ Combines the initial path of the environment with that of the Lean installation.
|
||||
def sharedLibPath (env : Env) : SearchPath :=
|
||||
env.lean.sharedLibPath ++ env.initSharedLibPath
|
||||
|
||||
/-- Unset toolchain-specific environment variables. -/
|
||||
def noToolchainVars : Array (String × Option String) :=
|
||||
#[
|
||||
("ELAN_TOOLCHAIN", none),
|
||||
("LAKE", none),
|
||||
("LAKE_OVERRIDE_LEAN", none),
|
||||
("LAKE_HOME", none),
|
||||
("LEAN", none),
|
||||
("LEAN_GITHASH", none),
|
||||
("LEAN_SYSROOT", none),
|
||||
("LEAN_AR", none)
|
||||
]
|
||||
|
||||
/-- Environment variable settings that are not augmented by a Lake workspace. -/
|
||||
def baseVars (env : Env) : Array (String × Option String) :=
|
||||
#[
|
||||
("ELAN", env.elan?.map (·.elan.toString)),
|
||||
("ELAN_HOME", env.elan?.map (·.home.toString)),
|
||||
("ELAN_TOOLCHAIN", if env.toolchain.isEmpty then none else env.toolchain),
|
||||
("LAKE", env.lake.lake.toString),
|
||||
("LAKE_HOME", env.lake.home.toString),
|
||||
("LAKE_PKG_URL_MAP", toJson env.pkgUrlMap |>.compress),
|
||||
("LEAN", env.lean.lean.toString),
|
||||
("LEAN_GITHASH", env.leanGithash),
|
||||
("LEAN_SYSROOT", env.lean.sysroot.toString),
|
||||
("LEAN_AR", env.lean.ar.toString),
|
||||
|
||||
@@ -9,16 +9,18 @@ import Lake.Config.Defaults
|
||||
open System
|
||||
namespace Lake
|
||||
|
||||
/-! ## Data Structures -/
|
||||
/-- Convert the string value of an environment variable to a boolean. -/
|
||||
def envToBool? (o : String) : Option Bool :=
|
||||
if ["y", "yes", "t", "true", "on", "1"].contains o.toLower then true
|
||||
else if ["n", "no", "f", "false", "off", "0"].contains o.toLower then false
|
||||
else none
|
||||
|
||||
/-- Standard path of `elan` in a Elan installation. -/
|
||||
def elanExe (home : FilePath) :=
|
||||
home / "bin" / "elan" |>.addExtension FilePath.exeExtension
|
||||
/-! ## Data Structures -/
|
||||
|
||||
/-- Information about the local Elan setup. -/
|
||||
structure ElanInstall where
|
||||
home : FilePath
|
||||
elan := elanExe home
|
||||
elan : FilePath
|
||||
binDir := home / "bin"
|
||||
toolchainsDir := home / "toolchains"
|
||||
deriving Inhabited, Repr
|
||||
@@ -57,7 +59,7 @@ def initSharedLib : FilePath :=
|
||||
/-- Path information about the local Lean installation. -/
|
||||
structure LeanInstall where
|
||||
sysroot : FilePath
|
||||
githash : String
|
||||
githash : String := ""
|
||||
srcDir := sysroot / "src" / "lean"
|
||||
leanLibDir := sysroot / "lib" / "lean"
|
||||
includeDir := sysroot / "include"
|
||||
@@ -67,9 +69,9 @@ structure LeanInstall where
|
||||
leanc := leancExe sysroot
|
||||
sharedLib := leanSharedLibDir sysroot / leanSharedLib
|
||||
initSharedLib := leanSharedLibDir sysroot / initSharedLib
|
||||
ar : FilePath
|
||||
cc : FilePath
|
||||
customCc : Bool
|
||||
ar : FilePath := "ar"
|
||||
cc : FilePath := "cc"
|
||||
customCc : Bool := false
|
||||
deriving Inhabited, Repr
|
||||
|
||||
/--
|
||||
@@ -110,12 +112,16 @@ def LakeInstall.ofLean (lean : LeanInstall) : LakeInstall where
|
||||
/-! ## Detection Functions -/
|
||||
|
||||
/--
|
||||
Attempt to detect a Elan installation by checking the `ELAN_HOME`
|
||||
environment variable for a installation location.
|
||||
Attempt to detect an Elan installation by checking the `ELAN` and `ELAN_HOME`
|
||||
environment variables. If `ELAN` is set but empty, Elan is considered disabled.
|
||||
-/
|
||||
def findElanInstall? : BaseIO (Option ElanInstall) := do
|
||||
if let some home ← IO.getEnv "ELAN_HOME" then
|
||||
return some {home}
|
||||
let elan := (← IO.getEnv "ELAN").getD "elan"
|
||||
if elan.trim.isEmpty then
|
||||
return none
|
||||
else
|
||||
return some {elan, home}
|
||||
return none
|
||||
|
||||
/--
|
||||
@@ -149,9 +155,9 @@ set to the empty string.
|
||||
|
||||
For (2), if `LEAN_AR` or `LEAN_CC` are defined, it uses those paths.
|
||||
Otherwise, if Lean is packaged with an `llvm-ar` and/or `clang`, use them.
|
||||
If not, use the `ar` and/or `cc` in the system's `PATH`. This last step is
|
||||
needed because internal builds of Lean do not bundle these tools
|
||||
(unlike user-facing releases).
|
||||
If not, use the `ar` and/or `cc` from the `AR` / `CC` environment variables
|
||||
or the system's `PATH`. This last step is needed because internal builds of
|
||||
Lean do not bundle these tools (unlike user-facing releases).
|
||||
|
||||
We also track whether `LEAN_CC` was set to determine whether it should
|
||||
be set in the future for `lake env`. This is because if `LEAN_CC` was not set,
|
||||
@@ -187,18 +193,29 @@ where
|
||||
return FilePath.mk ar
|
||||
else
|
||||
let ar := leanArExe sysroot
|
||||
if (← ar.pathExists) then pure ar else pure "ar"
|
||||
if (← ar.pathExists) then
|
||||
return ar
|
||||
else if let some ar ← IO.getEnv "AR" then
|
||||
return ar
|
||||
else
|
||||
return "ar"
|
||||
findCc := do
|
||||
if let some cc ← IO.getEnv "LEAN_CC" then
|
||||
return (FilePath.mk cc, true)
|
||||
else
|
||||
let cc := leanCcExe sysroot
|
||||
let cc := if (← cc.pathExists) then cc else "cc"
|
||||
let cc ←
|
||||
if (← cc.pathExists) then
|
||||
pure cc
|
||||
else if let some cc ← IO.getEnv "CC" then
|
||||
pure cc
|
||||
else
|
||||
pure "cc"
|
||||
return (cc, false)
|
||||
|
||||
/--
|
||||
Attempt to detect the installation of the given `lean` command
|
||||
by calling `findLeanCmdHome?`. See `LeanInstall.get` for how it assumes the
|
||||
by calling `findLeanSysroot?`. See `LeanInstall.get` for how it assumes the
|
||||
Lean install is organized.
|
||||
-/
|
||||
def findLeanCmdInstall? (lean := "lean") : BaseIO (Option LeanInstall) :=
|
||||
@@ -235,14 +252,28 @@ def getLakeInstall? (lake : FilePath) : BaseIO (Option LakeInstall) := do
|
||||
return none
|
||||
|
||||
/--
|
||||
Attempt to detect Lean's installation by first checking the
|
||||
`LEAN_SYSROOT` environment variable and then by trying `findLeanCmdHome?`.
|
||||
Attempt to detect Lean's installation by using the `LEAN` and `LEAN_SYSROOT`
|
||||
environment variables.
|
||||
|
||||
If `LEAN_SYSROOT` is set, use it. Otherwise, check `LEAN` for the `lean`
|
||||
executable. If `LEAN` is set but empty, Lean will be considered disabled.
|
||||
Otherwise, Lean's location will be determined by trying `findLeanSysroot?`
|
||||
using value of `LEAN` or, if unset, the `lean` in `PATH`.
|
||||
|
||||
See `LeanInstall.get` for how it assumes the Lean install is organized.
|
||||
-/
|
||||
def findLeanInstall? : BaseIO (Option LeanInstall) := do
|
||||
if let some sysroot ← IO.getEnv "LEAN_SYSROOT" then
|
||||
return some <| ← LeanInstall.get sysroot
|
||||
if let some sysroot ← findLeanSysroot? then
|
||||
let lean ← do
|
||||
if let some lean ← IO.getEnv "LEAN" then
|
||||
if lean.trim.isEmpty then
|
||||
return none
|
||||
else
|
||||
pure lean
|
||||
else
|
||||
pure "lean"
|
||||
if let some sysroot ← findLeanSysroot? lean then
|
||||
return some <| ← LeanInstall.get sysroot
|
||||
return none
|
||||
|
||||
@@ -271,7 +302,8 @@ Then it attempts to detect if Lake and Lean are part of a single installation
|
||||
where the `lake` executable is co-located with the `lean` executable (i.e., they
|
||||
are in the same directory). If Lean and Lake are not co-located, Lake will
|
||||
attempt to find the their installations separately by calling
|
||||
`findLeanInstall?` and `findLakeInstall?`.
|
||||
`findLeanInstall?` and `findLakeInstall?`. Setting `LAKE_OVERRIDE_LEAN` to true
|
||||
will force Lake to use `findLeanInstall?` even if co-located.
|
||||
|
||||
When co-located, Lake will assume that Lean and Lake's binaries are located in
|
||||
`<sysroot>/bin`, their Lean libraries in `<sysroot>/lib/lean`, Lean's source files
|
||||
@@ -280,9 +312,13 @@ following the pattern of a regular Lean toolchain.
|
||||
-/
|
||||
def findInstall? : BaseIO (Option ElanInstall × Option LeanInstall × Option LakeInstall) := do
|
||||
let elan? ← findElanInstall?
|
||||
if let some home ← findLakeLeanJointHome? then
|
||||
let lean ← LeanInstall.get home (collocated := true)
|
||||
let lake := LakeInstall.ofLean lean
|
||||
return (elan?, lean, lake)
|
||||
if let some sysroot ← findLakeLeanJointHome? then
|
||||
if (← IO.getEnv "LAKE_OVERRIDE_LEAN").bind envToBool? |>.getD false then
|
||||
let lake := LakeInstall.ofLean {sysroot}
|
||||
return (elan?, ← findLeanInstall?, lake)
|
||||
else
|
||||
let lean ← LeanInstall.get sysroot (collocated := true)
|
||||
let lake := LakeInstall.ofLean lean
|
||||
return (elan?, lean, lake)
|
||||
else
|
||||
return (elan?, ← findLeanInstall?, ← findLakeInstall?)
|
||||
|
||||
@@ -45,6 +45,10 @@ abbrev MonadLake (m : Type → Type u) :=
|
||||
@[inline] def mkLakeContext (ws : Workspace) : Lake.Context where
|
||||
opaqueWs := ws
|
||||
|
||||
/-- Run a `LakeT` monad in the context of this workspace. -/
|
||||
@[inline] def Workspace.runLakeT (ws : Workspace) (x : LakeT m α) : m α :=
|
||||
x.run (mkLakeContext ws)
|
||||
|
||||
instance [MonadWorkspace m] [Functor m] : MonadLake m where
|
||||
read := (mkLakeContext ·) <$> getWorkspace
|
||||
|
||||
|
||||
@@ -8,9 +8,6 @@ import Lake.Util.Opaque
|
||||
|
||||
namespace Lake
|
||||
|
||||
/-- Opaque reference to a `Package` used for forward declaration. -/
|
||||
declare_opaque_type OpaquePackage
|
||||
|
||||
/-- Opaque reference to a `Workspace` used for forward declaration. -/
|
||||
declare_opaque_type OpaqueWorkspace
|
||||
|
||||
|
||||
@@ -380,11 +380,9 @@ structure Package where
|
||||
/-- The path to the package's JSON manifest of remote dependencies (relative to `dir`). -/
|
||||
relManifestFile : FilePath := config.manifestFile.getD defaultManifestFile
|
||||
/-- The package's scope (e.g., in Reservoir). -/
|
||||
scope : String := ""
|
||||
scope : String
|
||||
/-- The URL to this package's Git remote. -/
|
||||
remoteUrl : String := ""
|
||||
/-- (Opaque references to) the package's direct dependencies. -/
|
||||
opaqueDeps : Array OpaquePackage := #[]
|
||||
remoteUrl : String
|
||||
/-- Dependency configurations for the package. -/
|
||||
depConfigs : Array Dependency := #[]
|
||||
/-- Lean library configurations for the package. -/
|
||||
@@ -419,8 +417,6 @@ instance : Nonempty Package :=
|
||||
have : Inhabited Environment := Classical.inhabited_of_nonempty inferInstance
|
||||
⟨by constructor <;> exact default⟩
|
||||
|
||||
hydrate_opaque_type OpaquePackage Package
|
||||
|
||||
instance : Hashable Package where hash pkg := hash pkg.config.name
|
||||
instance : BEq Package where beq p1 p2 := p1.config.name == p2.config.name
|
||||
|
||||
@@ -508,10 +504,6 @@ namespace Package
|
||||
@[inline] def readmeFile (self : Package) : FilePath :=
|
||||
self.dir / self.config.readmeFile
|
||||
|
||||
/-- The package's direct dependencies. -/
|
||||
@[inline] def deps (self : Package) : Array Package :=
|
||||
self.opaqueDeps.map (·.get)
|
||||
|
||||
/-- The path to the package's Lake directory relative to `dir` (e.g., `.lake`). -/
|
||||
@[inline] def relLakeDir (_ : Package) : FilePath :=
|
||||
defaultLakeDir
|
||||
|
||||
@@ -18,8 +18,14 @@ open Lean (Name)
|
||||
structure Workspace : Type where
|
||||
/-- The root package of the workspace. -/
|
||||
root : Package
|
||||
/-- The detect `Lake.Env` of the workspace. -/
|
||||
/-- The detected `Lake.Env` of the workspace. -/
|
||||
lakeEnv : Lake.Env
|
||||
/--
|
||||
The CLI arguments Lake was run with.
|
||||
Used by `lake update` to perform a restart of Lake on a toolchain update.
|
||||
A value of `none` means that Lake is not restartable via the CLI.
|
||||
-/
|
||||
lakeArgs? : Option (Array String) := none
|
||||
/-- The packages within the workspace (in `require` declaration order). -/
|
||||
packages : Array Package := {}
|
||||
/-- Name-package map of packages within the workspace. -/
|
||||
@@ -77,7 +83,7 @@ def addPackage (pkg : Package) (self : Workspace) : Workspace :=
|
||||
|
||||
/-- Try to find a script in the workspace with the given name. -/
|
||||
protected def findScript? (script : Name) (self : Workspace) : Option Script :=
|
||||
self.packages.findSomeRev? (·.scripts.find? script)
|
||||
self.packages.findSome? (·.scripts.find? script)
|
||||
|
||||
/-- Check if the module is local to any package in the workspace. -/
|
||||
def isLocalModule (mod : Name) (self : Workspace) : Bool :=
|
||||
@@ -89,27 +95,27 @@ def isBuildableModule (mod : Name) (self : Workspace) : Bool :=
|
||||
|
||||
/-- Locate the named, buildable, importable, local module in the workspace. -/
|
||||
protected def findModule? (mod : Name) (self : Workspace) : Option Module :=
|
||||
self.packages.findSomeRev? (·.findModule? mod)
|
||||
self.packages.findSome? (·.findModule? mod)
|
||||
|
||||
/-- Locate the named, buildable, but not necessarily importable, module in the workspace. -/
|
||||
def findTargetModule? (mod : Name) (self : Workspace) : Option Module :=
|
||||
self.packages.findSomeRev? (·.findTargetModule? mod)
|
||||
self.packages.findSome? (·.findTargetModule? mod)
|
||||
|
||||
/-- Try to find a Lean library in the workspace with the given name. -/
|
||||
protected def findLeanLib? (name : Name) (self : Workspace) : Option LeanLib :=
|
||||
self.packages.findSomeRev? fun pkg => pkg.findLeanLib? name
|
||||
self.packages.findSome? fun pkg => pkg.findLeanLib? name
|
||||
|
||||
/-- Try to find a Lean executable in the workspace with the given name. -/
|
||||
protected def findLeanExe? (name : Name) (self : Workspace) : Option LeanExe :=
|
||||
self.packages.findSomeRev? fun pkg => pkg.findLeanExe? name
|
||||
self.packages.findSome? fun pkg => pkg.findLeanExe? name
|
||||
|
||||
/-- Try to find an external library in the workspace with the given name. -/
|
||||
protected def findExternLib? (name : Name) (self : Workspace) : Option ExternLib :=
|
||||
self.packages.findSomeRev? fun pkg => pkg.findExternLib? name
|
||||
self.packages.findSome? fun pkg => pkg.findExternLib? name
|
||||
|
||||
/-- Try to find a target configuration in the workspace with the given name. -/
|
||||
def findTargetConfig? (name : Name) (self : Workspace) : Option ((pkg : Package) × TargetConfig pkg.name name) :=
|
||||
self.packages.findSomeRev? fun pkg => pkg.findTargetConfig? name <&> (⟨pkg, ·⟩)
|
||||
self.packages.findSome? fun pkg => pkg.findTargetConfig? name <&> (⟨pkg, ·⟩)
|
||||
|
||||
/-- Add a module facet to the workspace. -/
|
||||
def addModuleFacetConfig (cfg : ModuleFacetConfig name) (self : Workspace) : Workspace :=
|
||||
@@ -137,15 +143,15 @@ def findLibraryFacetConfig? (name : Name) (self : Workspace) : Option (LibraryFa
|
||||
|
||||
/-- The workspace's binary directories (which are added to `Path`). -/
|
||||
def binPath (self : Workspace) : SearchPath :=
|
||||
self.packages.foldr (fun pkg dirs => pkg.binDir :: dirs) []
|
||||
self.packages.foldl (fun dirs pkg => pkg.binDir :: dirs) []
|
||||
|
||||
/-- The workspace's Lean library directories (which are added to `LEAN_PATH`). -/
|
||||
def leanPath (self : Workspace) : SearchPath :=
|
||||
self.packages.foldr (fun pkg dirs => pkg.leanLibDir :: dirs) []
|
||||
self.packages.foldl (fun dirs pkg => pkg.leanLibDir :: dirs) []
|
||||
|
||||
/-- The workspace's source directories (which are added to `LEAN_SRC_PATH`). -/
|
||||
def leanSrcPath (self : Workspace) : SearchPath :=
|
||||
self.packages.foldr (init := {}) fun pkg dirs =>
|
||||
self.packages.foldl (init := {}) fun dirs pkg =>
|
||||
pkg.leanLibConfigs.foldr (init := dirs) fun cfg dirs =>
|
||||
pkg.srcDir / cfg.srcDir :: dirs
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import Lean.Data.Options
|
||||
import Lake.Config.Defaults
|
||||
import Lake.Config.Env
|
||||
import Lake.Util.Log
|
||||
import Lake.Util.Version
|
||||
|
||||
namespace Lake
|
||||
open System Lean
|
||||
@@ -16,6 +17,12 @@ open System Lean
|
||||
structure LoadConfig where
|
||||
/-- The Lake environment of the load process. -/
|
||||
lakeEnv : Lake.Env
|
||||
/--
|
||||
The CLI arguments Lake was run with.
|
||||
Used to perform a restart of Lake on a toolchain update.
|
||||
A value of `none` means that Lake is not restartable via the CLI.
|
||||
-/
|
||||
lakeArgs? : Option (Array String) := none
|
||||
/-- The root directory of the Lake workspace. -/
|
||||
wsDir : FilePath
|
||||
/-- The directory of the loaded package (relative to the root). -/
|
||||
@@ -26,8 +33,15 @@ structure LoadConfig where
|
||||
lakeOpts : NameMap String := {}
|
||||
/-- The Lean options with which to elaborate the configuration file. -/
|
||||
leanOpts : Options := {}
|
||||
/-- If `true`, Lake will elaborate configuration files instead of using OLeans. -/
|
||||
/-- Whether Lake should re-elaborate configuration files instead of using cached OLeans. -/
|
||||
reconfigure : Bool := false
|
||||
/-- Whether to update dependencies when loading the workspace. -/
|
||||
updateDeps : Bool := false
|
||||
/--
|
||||
Whether to update the workspace's `lean-toolchain` when dependencies are updated.
|
||||
If `true` and a toolchain update occurs, Lake will need to be restarted.
|
||||
-/
|
||||
updateToolchain : Bool := true
|
||||
/-- The package's scope (e.g., in Reservoir). -/
|
||||
scope : String := ""
|
||||
/-- The URL to this package's Git remote (if any). -/
|
||||
|
||||
@@ -20,31 +20,36 @@ or resolve a local path dependency.
|
||||
namespace Lake
|
||||
|
||||
/-- Update the Git package in `repo` to `rev` if not already at it. -/
|
||||
def updateGitPkg (name : String) (repo : GitRepo) (rev? : Option String) : LogIO PUnit := do
|
||||
def updateGitPkg
|
||||
(name : String) (repo : GitRepo) (rev? : Option String)
|
||||
: LogIO PUnit := do
|
||||
let rev ← repo.findRemoteRevision rev?
|
||||
if (← repo.getHeadRevision) = rev then
|
||||
if (← repo.hasDiff) then
|
||||
logWarning s!"{name}: repository '{repo.dir}' has local changes"
|
||||
else
|
||||
logInfo s!"{name}: updating repository '{repo.dir}' to revision '{rev}'"
|
||||
logInfo s!"{name}: checking out revision '{rev}'"
|
||||
repo.checkoutDetach rev
|
||||
|
||||
/-- Clone the Git package as `repo`. -/
|
||||
def cloneGitPkg (name : String) (repo : GitRepo)
|
||||
(url : String) (rev? : Option String) : LogIO PUnit := do
|
||||
logInfo s!"{name}: cloning {url} to '{repo.dir}'"
|
||||
def cloneGitPkg
|
||||
(name : String) (repo : GitRepo) (url : String) (rev? : Option String)
|
||||
: LogIO PUnit := do
|
||||
logInfo s!"{name}: cloning {url}"
|
||||
repo.clone url
|
||||
if let some rev := rev? then
|
||||
let hash ← repo.resolveRemoteRevision rev
|
||||
repo.checkoutDetach hash
|
||||
let rev ← repo.resolveRemoteRevision rev
|
||||
logInfo s!"{name}: checking out revision '{rev}'"
|
||||
repo.checkoutDetach rev
|
||||
|
||||
/--
|
||||
Update the Git repository from `url` in `repo` to `rev?`.
|
||||
If `repo` is already from `url`, just checkout the new revision.
|
||||
Otherwise, delete the local repository and clone a fresh copy from `url`.
|
||||
-/
|
||||
def updateGitRepo (name : String) (repo : GitRepo)
|
||||
(url : String) (rev? : Option String) : LogIO Unit := do
|
||||
def updateGitRepo
|
||||
(name : String) (repo : GitRepo) (url : String) (rev? : Option String)
|
||||
: LogIO Unit := do
|
||||
let sameUrl ← EIO.catchExceptions (h := fun _ => pure false) <| show IO Bool from do
|
||||
let some remoteUrl ← repo.getRemoteUrl? | return false
|
||||
if remoteUrl = url then return true
|
||||
@@ -65,8 +70,9 @@ def updateGitRepo (name : String) (repo : GitRepo)
|
||||
Materialize the Git repository from `url` into `repo` at `rev?`.
|
||||
Clone it if no local copy exists, otherwise update it.
|
||||
-/
|
||||
def materializeGitRepo (name : String) (repo : GitRepo)
|
||||
(url : String) (rev? : Option String) : LogIO Unit := do
|
||||
def materializeGitRepo
|
||||
(name : String) (repo : GitRepo) (url : String) (rev? : Option String)
|
||||
: LogIO Unit := do
|
||||
if (← repo.dirExists) then
|
||||
updateGitRepo name repo url rev?
|
||||
else
|
||||
@@ -110,11 +116,7 @@ def Dependency.materialize
|
||||
match src with
|
||||
| .path dir =>
|
||||
let relPkgDir := relParentDir / dir
|
||||
return {
|
||||
relPkgDir
|
||||
remoteUrl := ""
|
||||
manifestEntry := mkEntry <| .path relPkgDir
|
||||
}
|
||||
return mkDep relPkgDir "" (.path relPkgDir)
|
||||
| .git url inputRev? subDir? => do
|
||||
let sname := dep.name.toString (escape := false)
|
||||
let repoUrl := Git.filterUrl? url |>.getD ""
|
||||
@@ -127,7 +129,7 @@ def Dependency.materialize
|
||||
if ver.startsWith "git#" then
|
||||
return ver.drop 4
|
||||
else
|
||||
error s!"{dep.name} unsupported dependency version format '{ver}' (should be \"git#>rev>\")"
|
||||
error s!"{dep.name}: unsupported dependency version format '{ver}' (should be \"git#>rev>\")"
|
||||
let depName := dep.name.toString (escape := false)
|
||||
let some pkg ← Reservoir.fetchPkg? lakeEnv dep.scope depName
|
||||
| error s!"{dep.scope}/{depName}: could not materialize package: \
|
||||
@@ -139,18 +141,17 @@ def Dependency.materialize
|
||||
(githubUrl?.getD "") (verRev? <|> defaultBranch?) subDir?
|
||||
| _ => error s!"{pkg.fullName}: Git source not found on Reservoir"
|
||||
where
|
||||
mkEntry src : PackageEntry :=
|
||||
{name := dep.name, scope := dep.scope, inherited, src}
|
||||
materializeGit name relPkgDir gitUrl remoteUrl inputRev? subDir? : LogIO MaterializedDep := do
|
||||
let repo := GitRepo.mk (wsDir / relPkgDir)
|
||||
let gitUrl := lakeEnv.pkgUrlMap.find? dep.name |>.getD gitUrl
|
||||
materializeGitRepo name repo gitUrl inputRev?
|
||||
let rev ← repo.getHeadRevision
|
||||
let relPkgDir := if let some subDir := subDir? then relPkgDir / subDir else relPkgDir
|
||||
return {
|
||||
relPkgDir, remoteUrl
|
||||
manifestEntry := mkEntry <| .git gitUrl rev inputRev? subDir?
|
||||
}
|
||||
return mkDep relPkgDir remoteUrl <| .git gitUrl rev inputRev? subDir?
|
||||
@[inline] mkDep relPkgDir remoteUrl src : MaterializedDep := {
|
||||
relPkgDir, remoteUrl,
|
||||
manifestEntry := {name := dep.name, scope := dep.scope, inherited, src}
|
||||
}
|
||||
|
||||
/--
|
||||
Materializes a manifest package entry, cloning and/or checking it out as necessary.
|
||||
@@ -161,11 +162,7 @@ def PackageEntry.materialize
|
||||
: LogIO MaterializedDep :=
|
||||
match manifestEntry.src with
|
||||
| .path (dir := relPkgDir) .. =>
|
||||
return {
|
||||
relPkgDir
|
||||
remoteUrl := ""
|
||||
manifestEntry
|
||||
}
|
||||
return mkDep relPkgDir ""
|
||||
| .git (url := url) (rev := rev) (subDir? := subDir?) .. => do
|
||||
let sname := manifestEntry.name.toString (escape := false)
|
||||
let relGitDir := relPkgsDir / sname
|
||||
@@ -188,8 +185,7 @@ def PackageEntry.materialize
|
||||
let url := lakeEnv.pkgUrlMap.find? manifestEntry.name |>.getD url
|
||||
cloneGitPkg sname repo url rev
|
||||
let relPkgDir := match subDir? with | .some subDir => relGitDir / subDir | .none => relGitDir
|
||||
return {
|
||||
relPkgDir
|
||||
remoteUrl := Git.filterUrl? url |>.getD ""
|
||||
manifestEntry
|
||||
}
|
||||
return mkDep relPkgDir (Git.filterUrl? url |>.getD "")
|
||||
where
|
||||
@[inline] mkDep relPkgDir remoteUrl : MaterializedDep :=
|
||||
{relPkgDir, remoteUrl, manifestEntry}
|
||||
|
||||
@@ -18,6 +18,21 @@ This module contains definitions for resolving the dependencies of a package.
|
||||
|
||||
namespace Lake
|
||||
|
||||
def stdMismatchError (newName : String) (rev : String) :=
|
||||
s!"the 'std' package has been renamed to '{newName}' and moved to the
|
||||
'leanprover-community' organization; downstream packages which wish to
|
||||
update to the new std should replace
|
||||
|
||||
require std from
|
||||
git \"https://github.com/leanprover/std4\"{rev}
|
||||
|
||||
in their Lake configuration file with
|
||||
|
||||
require {newName} from
|
||||
git \"https://github.com/leanprover-community/{newName}\"{rev}
|
||||
|
||||
"
|
||||
|
||||
/--
|
||||
Loads the package configuration of a materialized dependency.
|
||||
Adds the facets defined in the package to the `Workspace`.
|
||||
@@ -43,100 +58,82 @@ def loadDepPackage
|
||||
else
|
||||
return (pkg, ws)
|
||||
|
||||
/-- The monad of the dependency resolver. -/
|
||||
abbrev ResolveT m := CallStackT Name <| StateT Workspace m
|
||||
/--
|
||||
The resolver's call stack of dependencies.
|
||||
That is, the dependency currently being resolved plus its parents.
|
||||
-/
|
||||
abbrev DepStack := CallStack Name
|
||||
|
||||
@[inline] nonrec def ResolveT.run (ws : Workspace) (x : ResolveT m α) (stack : CallStack Name := {}) : m (α × Workspace) :=
|
||||
x.run stack |>.run ws
|
||||
/--
|
||||
A monad transformer for recursive dependency resolution.
|
||||
It equips the monad with the stack of dependencies currently being resolved.
|
||||
-/
|
||||
abbrev DepStackT m := CallStackT Name m
|
||||
|
||||
@[inline] nonrec def DepStackT.run
|
||||
(x : DepStackT m α) (stack : DepStack := {})
|
||||
: m α :=
|
||||
x.run stack
|
||||
|
||||
/-- Log dependency cycle and error. -/
|
||||
@[specialize] def depCycleError [MonadError m] (cycle : Cycle Name) : m α :=
|
||||
error s!"dependency cycle detected:\n{"\n".intercalate <| cycle.map (s!" {·}")}"
|
||||
|
||||
instance [Monad m] [MonadError m] : MonadCycleOf Name (ResolveT m) where
|
||||
instance [Monad m] [MonadError m] : MonadCycleOf Name (DepStackT m) where
|
||||
throwCycle := depCycleError
|
||||
|
||||
/--
|
||||
Recursively visits the workspace dependency graph, starting from `root`.
|
||||
At each package, loops through each direct dependency performing just `breath`.
|
||||
Them, loops again through the results applying `depth`, recursing, and adding
|
||||
the package to workspace's package set. Errors if a cycle is encountered.
|
||||
/-- The monad of the dependency resolver. -/
|
||||
abbrev ResolveT m := DepStackT <| StateT Workspace m
|
||||
|
||||
**Traversal Order**
|
||||
@[inline] nonrec def ResolveT.run
|
||||
(ws : Workspace) (x : ResolveT m α) (stack : DepStack := {})
|
||||
: m (α × Workspace) :=
|
||||
x.run stack |>.run ws
|
||||
|
||||
All dependencies of a package are visited in order before recursing to the
|
||||
dependencies' dependencies. For example, given the dependency graph:
|
||||
|
||||
```
|
||||
R
|
||||
|- A
|
||||
|- B
|
||||
|- X
|
||||
|- Y
|
||||
|- C
|
||||
```
|
||||
|
||||
Lake follows the order `R`, `A`, `B`, `C`, `X`, `Y`.
|
||||
|
||||
The logic behind this design is that users would expect the dependencies
|
||||
they write in a package configuration to be resolved accordingly and would be
|
||||
surprised if they are overridden by nested dependencies referring to the same
|
||||
package.
|
||||
|
||||
For example, were Lake to use a pure depth-first traversal, Lake would follow
|
||||
the order `R`, `A`, `B`, `X`, `Y`, `C`. If `X` and `C` are both the package
|
||||
`foo`, Lake would use the configuration of `foo` found in `B` rather than in
|
||||
the root `R`, which would likely confuse the user.
|
||||
-/
|
||||
@[specialize] def Workspace.resolveDeps
|
||||
/-- Recursively run a `ResolveT` monad starting from the workspace's root. -/
|
||||
@[specialize] private def Workspace.runResolveT
|
||||
[Monad m] [MonadError m] (ws : Workspace)
|
||||
(breadth : Package → Dependency → ResolveT m Package)
|
||||
(depth : Package → m PUnit := fun _ => pure ())
|
||||
(go : RecFetchFn Package PUnit (ResolveT m))
|
||||
(root := ws.root) (stack : DepStack := {})
|
||||
: m Workspace := do
|
||||
let (root, ws) ← ResolveT.run ws <| StateT.run' (s := {}) <|
|
||||
inline <| recFetchAcyclic (·.name) go ws.root
|
||||
return {ws with root}
|
||||
let (_, ws) ← ResolveT.run ws (stack := stack) do
|
||||
inline <| recFetchAcyclic (·.name) go root
|
||||
return ws
|
||||
|
||||
/-
|
||||
Recursively visits each node in a package's dependency graph, starting from
|
||||
the workspace package `root`. Each dependency missing from the workspace is
|
||||
resolved using the `resolve` function and added into the workspace.
|
||||
|
||||
Recursion occurs breadth-first. Each direct dependency of a package is
|
||||
resolved in reverse order before recursing to the dependencies' dependencies.
|
||||
|
||||
See `Workspace.updateAndMaterializeCore` for more details.
|
||||
-/
|
||||
@[inline] private def Workspace.resolveDepsCore
|
||||
[Monad m] [MonadError m] (ws : Workspace)
|
||||
(load : Package → Dependency → StateT Workspace m Package)
|
||||
(root : Package := ws.root) (stack : DepStack := {})
|
||||
: m Workspace := do
|
||||
ws.runResolveT go root stack
|
||||
where
|
||||
@[specialize] go pkg resolve : StateT (NameMap Package) (ResolveT m) Package := do
|
||||
pkg.depConfigs.forM fun dep => do
|
||||
if (← getThe (NameMap Package)).contains dep.name then
|
||||
return
|
||||
if (← getThe Workspace).packageMap.contains dep.name then
|
||||
return -- already resolved in another branch
|
||||
@[specialize] go pkg recurse : ResolveT m Unit := do
|
||||
let start := (← getWorkspace).packages.size
|
||||
-- Materialize and load the missing direct dependencies of `pkg`
|
||||
pkg.depConfigs.forRevM fun dep => do
|
||||
let ws ← getWorkspace
|
||||
if ws.packageMap.contains dep.name then
|
||||
return -- already handled in another branch
|
||||
if pkg.name = dep.name then
|
||||
error s!"{pkg.name}: package requires itself (or a package with the same name)"
|
||||
let pre ← breadth pkg dep -- package w/o dependencies
|
||||
store dep.name pre
|
||||
let deps ← pkg.depConfigs.mapM fun dep => do
|
||||
if let some pre ← fetch? dep.name then
|
||||
modifyThe (NameMap Package) (·.erase dep.name) -- for `dep` linearity
|
||||
depth pre
|
||||
return OpaquePackage.mk (← resolve pre)
|
||||
if let some dep ← findPackage? dep.name then
|
||||
return OpaquePackage.mk dep -- already resolved in another branch
|
||||
error s!"{dep.name}: impossible resolution state reached"
|
||||
let pkg := {pkg with opaqueDeps := deps}
|
||||
modifyThe Workspace (·.addPackage pkg)
|
||||
return pkg
|
||||
|
||||
def stdMismatchError (newName : String) (rev : String) :=
|
||||
s!"the 'std' package has been renamed to '{newName}' and moved to the
|
||||
'leanprover-community' organization; downstream packages which wish to
|
||||
update to the new std should replace
|
||||
|
||||
require std from
|
||||
git \"https://github.com/leanprover/std4\"{rev}
|
||||
|
||||
in their Lake configuration file with
|
||||
|
||||
require {newName} from
|
||||
git \"https://github.com/leanprover-community/{newName}\"{rev}
|
||||
|
||||
"
|
||||
let depPkg ← load pkg dep
|
||||
modifyThe Workspace (·.addPackage depPkg)
|
||||
-- Recursively load the dependencies' dependencies
|
||||
(← getWorkspace).packages.forM recurse start
|
||||
|
||||
/--
|
||||
The monad of the manifest updater.
|
||||
It is equipped with and entry map entries for the updated manifest.
|
||||
Adds monad state used to update the manifest.
|
||||
It equips the monad with a map of locked dependencies.
|
||||
-/
|
||||
abbrev UpdateT := StateT (NameMap PackageEntry)
|
||||
|
||||
@@ -147,7 +144,9 @@ abbrev UpdateT := StateT (NameMap PackageEntry)
|
||||
Reuse manifest versions of root packages that should not be updated.
|
||||
Also, move the packages directory if its location has changed.
|
||||
-/
|
||||
def reuseManifest (ws : Workspace) (toUpdate : NameSet) : UpdateT LogIO PUnit := do
|
||||
private def reuseManifest
|
||||
(ws : Workspace) (toUpdate : NameSet)
|
||||
: UpdateT LogIO PUnit := do
|
||||
let rootName := ws.root.name.toString (escape := false)
|
||||
match (← Manifest.load ws.manifestFile |>.toBaseIO) with
|
||||
| .ok manifest =>
|
||||
@@ -175,7 +174,7 @@ def reuseManifest (ws : Workspace) (toUpdate : NameSet) : UpdateT LogIO PUnit :=
|
||||
logWarning s!"{rootName}: ignoring previous manifest because it failed to load: {e}"
|
||||
|
||||
/-- Add a package dependency's manifest entries to the update state. -/
|
||||
def addDependencyEntries (pkg : Package) : UpdateT LogIO PUnit := do
|
||||
private def addDependencyEntries (pkg : Package) : UpdateT LogIO PUnit := do
|
||||
match (← Manifest.load pkg.manifestFile |>.toBaseIO) with
|
||||
| .ok manifest =>
|
||||
manifest.packages.forM fun entry => do
|
||||
@@ -187,22 +186,31 @@ def addDependencyEntries (pkg : Package) : UpdateT LogIO PUnit := do
|
||||
| .error e =>
|
||||
logWarning s!"{pkg.name}: ignoring manifest because it failed to load: {e}"
|
||||
|
||||
/-- Update a single dependency. -/
|
||||
def updateDep
|
||||
(pkg : Package) (dep : Dependency) (leanOpts : Options := {})
|
||||
: ResolveT (UpdateT LogIO) Package := do
|
||||
let ws ← getThe Workspace
|
||||
let inherited := pkg.name != ws.root.name
|
||||
-- Materialize the dependency
|
||||
let matDep ← id do
|
||||
if let some entry ← fetch? dep.name then
|
||||
entry.materialize ws.lakeEnv ws.dir ws.relPkgsDir
|
||||
else
|
||||
let matDep ← dep.materialize inherited ws.lakeEnv ws.dir ws.relPkgsDir pkg.relDir
|
||||
store matDep.name matDep.manifestEntry
|
||||
return matDep
|
||||
-- Load the package
|
||||
let depPkg ← loadDepPackage matDep dep.opts leanOpts true
|
||||
/-- Materialize a single dependency, updating it if desired. -/
|
||||
private def updateAndMaterializeDep
|
||||
(ws : Workspace) (pkg : Package) (dep : Dependency)
|
||||
: UpdateT LogIO MaterializedDep := do
|
||||
if let some entry ← fetch? dep.name then
|
||||
entry.materialize ws.lakeEnv ws.dir ws.relPkgsDir
|
||||
else
|
||||
let inherited := pkg.name ≠ ws.root.name
|
||||
/-
|
||||
NOTE: A path dependency inherited from another dependency's manifest
|
||||
will always be of the form a `./<relPath>` (i.e., be relative to its
|
||||
workspace). Thus, when relativized to this workspace, it will have the
|
||||
path `<relPkgDir>/./<relPath>`. However, if defining dependency lacks
|
||||
a manifest, it will instead be locked as `<relPkgDir>/<relPath>`.
|
||||
Adding a `.` here eliminates this difference.
|
||||
-/
|
||||
let relPkgDir := if pkg.relDir == "." then pkg.relDir else pkg.relDir / "."
|
||||
let matDep ← dep.materialize inherited ws.lakeEnv ws.dir ws.relPkgsDir relPkgDir
|
||||
store matDep.name matDep.manifestEntry
|
||||
return matDep
|
||||
|
||||
/-- Verify that a dependency was loaded with the correct name. -/
|
||||
private def validateDep
|
||||
(pkg : Package) (dep : Dependency) (matDep : MaterializedDep) (depPkg : Package)
|
||||
: LogIO PUnit := do
|
||||
if depPkg.name ≠ dep.name then
|
||||
if dep.name = .mkSimple "std" then
|
||||
let rev :=
|
||||
@@ -216,24 +224,144 @@ def updateDep
|
||||
logError s!"'{dep.name}' was downloaded incorrectly; \
|
||||
you will need to manually delete '{depPkg.dir}': {e}"
|
||||
error s!"{pkg.name}: package '{depPkg.name}' was required as '{dep.name}'"
|
||||
return depPkg
|
||||
|
||||
/--
|
||||
Rebuild the workspace's Lake manifest and materialize missing dependencies.
|
||||
|
||||
Packages are updated to latest specific revision matching that in `require`
|
||||
(e.g., if the `require` is `@master`, update to latest commit on master) or
|
||||
removed if the `require` is removed. If `tuUpdate` is empty, update/remove all
|
||||
root dependencies. Otherwise, only update the root dependencies specified.
|
||||
|
||||
Package are always reconfigured when updated.
|
||||
Exit code returned if Lake needs a manual restart.
|
||||
Used, for instance, if the toolchain is updated and no Elan is detected.
|
||||
-/
|
||||
def Workspace.updateAndMaterialize
|
||||
(ws : Workspace) (toUpdate : NameSet := {}) (leanOpts : Options := {})
|
||||
: LogIO Workspace := do
|
||||
let (ws, entries) ← UpdateT.run do
|
||||
reuseManifest ws toUpdate
|
||||
ws.resolveDeps (updateDep · · leanOpts) (addDependencyEntries ·)
|
||||
def restartCode : ExitCode := 4
|
||||
|
||||
/--
|
||||
Update the workspace's `lean-toolchain` if necessary.
|
||||
|
||||
Compares the root's toolchain with that of its direct dependencies to find the
|
||||
best match. If none can be found, issue warning and return normally. If an
|
||||
update is found
|
||||
-/
|
||||
def Workspace.updateToolchain
|
||||
(ws : Workspace) (rootDeps : Array MaterializedDep)
|
||||
: LoggerIO PUnit := do
|
||||
let rootToolchainFile := ws.root.dir / toolchainFileName
|
||||
let rootTc? ← ToolchainVer.ofDir? ws.dir
|
||||
let (src, tc?, tcs) ← rootDeps.foldlM (init := (ws.root.name, rootTc?, #[])) fun s dep => do
|
||||
let depTc? ← ToolchainVer.ofDir? (ws.dir / dep.relPkgDir)
|
||||
let some depTc := depTc?
|
||||
| return s
|
||||
let (src, tc?, tcs) := s
|
||||
let some tc := tc?
|
||||
| return (dep.name, depTc?, tcs)
|
||||
if depTc ≤ tc then
|
||||
return (src, tc, tcs)
|
||||
else if tc < depTc then
|
||||
return (dep.name, depTc, tcs)
|
||||
else
|
||||
return (src, tc, tcs.push (dep.name, depTc))
|
||||
if 0 < tcs.size then
|
||||
let s := "toolchain not updated; multiple toolchain candidates:"
|
||||
let s := if let some tc := tc? then s!"{s}\n {tc}\n from {src}" else s
|
||||
let s := tcs.foldl (init := s) fun s (d, tc) => s!"{s}\n {tc}\n from {d}"
|
||||
logWarning s
|
||||
else if let some tc := tc? then
|
||||
if rootTc?.any (· == tc) then
|
||||
logInfo "toolchain not updated; already up-to-date"
|
||||
return
|
||||
logInfo s!"updating toolchain to '{tc}'"
|
||||
IO.FS.writeFile rootToolchainFile tc.toString
|
||||
let some lakeArgs := ws.lakeArgs?
|
||||
| logInfo s!"cannot auto-restart; you will need to manually restart Lake"
|
||||
IO.Process.exit restartCode.toUInt8
|
||||
let some elanInstall := ws.lakeEnv.elan?
|
||||
| logInfo s!"no Elan detected; you will need to manually restart Lake"
|
||||
IO.Process.exit restartCode.toUInt8
|
||||
logInfo s!"restarting Lake via Elan"
|
||||
let child ← IO.Process.spawn {
|
||||
cmd := elanInstall.elan.toString
|
||||
args := #["run", "--install", tc.toString, "lake"] ++ lakeArgs
|
||||
env := Env.noToolchainVars
|
||||
}
|
||||
IO.Process.exit (← child.wait).toUInt8
|
||||
else
|
||||
logInfo s!"toolchain not updated; no toolchain information found"
|
||||
|
||||
/--
|
||||
Updates the workspace, materializing and reconfiguring dependencies.
|
||||
|
||||
Dependencies are updated to latest specific revision matching that in `require`
|
||||
(e.g., if the `require` is `@master`, update to latest commit on master) or
|
||||
removed if the `require` is removed.
|
||||
If `tuUpdate` is empty, all direct dependencies of the workspace's root will be
|
||||
updated and/or remove. Otherwise, only those specified will be updated.
|
||||
|
||||
If `updateToolchain := true`, the workspace's toolchain is also updated to the
|
||||
latest toolchain compatible with the root and its direct dependencies.
|
||||
If there are multiple incomparable toolchain versions across them,
|
||||
a warning will be issued and no update performed.
|
||||
If an update is performed, Lake will automatically restart the update on the new
|
||||
toolchain (via `elan`). If `elan` is missing, it will instead request a manual
|
||||
restart from the user and exit immediately with `restartCode`.
|
||||
|
||||
**Dependency Traversal Order**
|
||||
|
||||
All dependencies of a package are visited in reverse order before recursing
|
||||
to the dependencies' dependencies. For example, given the dependency graph:
|
||||
|
||||
```
|
||||
R
|
||||
|- A
|
||||
|- B
|
||||
|- X
|
||||
|- Y
|
||||
|- C
|
||||
```
|
||||
|
||||
Lake follows the order `R`, `C`, `A`, `B`, `Y`, `X`.
|
||||
|
||||
The reason for this is two-fold:
|
||||
1. Like targets, later requires should shadow earlier definitions.
|
||||
2. Requires written by a user should take priority over those inherited
|
||||
from dependencies.
|
||||
|
||||
Were Lake to use a depth-first traversal, for example, Lake would follow
|
||||
the order `R`, `A`, `B`, `X`, `Y`, `C`. If `X` and `C` are both the package
|
||||
`foo`, Lake would use the configuration of `foo` found in `B` rather than in
|
||||
the root `R`, which would likely confuse the user.
|
||||
-/
|
||||
def Workspace.updateAndMaterializeCore
|
||||
(ws : Workspace)
|
||||
(toUpdate : NameSet := {}) (leanOpts : Options := {})
|
||||
(updateToolchain := true)
|
||||
: LoggerIO (Workspace × NameMap PackageEntry) := UpdateT.run do
|
||||
reuseManifest ws toUpdate
|
||||
let ws := ws.addPackage ws.root
|
||||
if updateToolchain then
|
||||
let deps := ws.root.depConfigs.reverse
|
||||
let matDeps ← deps.mapM fun dep => do
|
||||
logVerbose s!"{ws.root.name}: updating '{dep.name}' with {toJson dep.opts}"
|
||||
updateAndMaterializeDep ws ws.root dep
|
||||
ws.updateToolchain matDeps
|
||||
let start := ws.packages.size
|
||||
let ws ← (deps.zip matDeps).foldlM (init := ws) fun ws (dep, matDep) => do
|
||||
let (depPkg, ws) ← loadUpdatedDep ws.root dep matDep ws
|
||||
let ws := ws.addPackage depPkg
|
||||
return ws
|
||||
ws.packages.foldlM (init := ws) (start := start) fun ws pkg =>
|
||||
ws.resolveDepsCore (stack := [ws.root.name]) updateAndLoadDep pkg
|
||||
else
|
||||
ws.resolveDepsCore updateAndLoadDep
|
||||
where
|
||||
@[inline] updateAndLoadDep pkg dep := do
|
||||
let matDep ← updateAndMaterializeDep (← getWorkspace) pkg dep
|
||||
loadUpdatedDep pkg dep matDep
|
||||
@[inline] loadUpdatedDep pkg dep matDep : StateT Workspace (UpdateT LogIO) Package := do
|
||||
let depPkg ← loadDepPackage matDep dep.opts leanOpts true
|
||||
validateDep pkg dep matDep depPkg
|
||||
addDependencyEntries depPkg
|
||||
return depPkg
|
||||
|
||||
/-- Write package entries to the workspace manifest. -/
|
||||
def Workspace.writeManifest
|
||||
(ws : Workspace) (entries : NameMap PackageEntry)
|
||||
: LogIO PUnit := do
|
||||
let manifestEntries := ws.packages.foldl (init := #[]) fun arr pkg =>
|
||||
match entries.find? pkg.name with
|
||||
| some entry => arr.push <|
|
||||
@@ -246,10 +374,28 @@ def Workspace.updateAndMaterialize
|
||||
packages := manifestEntries
|
||||
}
|
||||
manifest.saveToFile ws.manifestFile
|
||||
LakeT.run ⟨ws⟩ <| ws.packages.forM fun pkg => do
|
||||
unless pkg.postUpdateHooks.isEmpty do
|
||||
logInfo s!"{pkg.name}: running post-update hooks"
|
||||
pkg.postUpdateHooks.forM fun hook => hook.get.fn pkg
|
||||
|
||||
/-- Run a package's `post_update` hooks. -/
|
||||
def Package.runPostUpdateHooks (pkg : Package) : LakeT LogIO PUnit := do
|
||||
unless pkg.postUpdateHooks.isEmpty do
|
||||
logInfo s!"{pkg.name}: running post-update hooks"
|
||||
pkg.postUpdateHooks.forM fun hook => hook.get.fn pkg
|
||||
|
||||
/--
|
||||
Updates the workspace, writes the new Lake manifest, and runs package
|
||||
post-update hooks.
|
||||
|
||||
See `Workspace.updateAndMaterializeCore` for details on the update process.
|
||||
-/
|
||||
def Workspace.updateAndMaterialize
|
||||
(ws : Workspace)
|
||||
(toUpdate : NameSet := {}) (leanOpts : Options := {})
|
||||
(updateToolchain := true)
|
||||
: LoggerIO Workspace := do
|
||||
let (ws, entries) ←
|
||||
ws.updateAndMaterializeCore toUpdate leanOpts updateToolchain
|
||||
ws.writeManifest entries
|
||||
ws.runLakeT do ws.packages.forM (·.runPostUpdateHooks)
|
||||
return ws
|
||||
|
||||
/--
|
||||
@@ -293,8 +439,9 @@ def Workspace.materializeDeps
|
||||
let pkgEntries : NameMap PackageEntry := manifest.packages.foldl (init := {})
|
||||
fun map entry => map.insert entry.name entry
|
||||
validateManifest pkgEntries ws.root.depConfigs
|
||||
ws.resolveDeps fun pkg dep => do
|
||||
let ws ← getThe Workspace
|
||||
let ws := ws.addPackage ws.root
|
||||
ws.resolveDepsCore fun pkg dep => do
|
||||
let ws ← getWorkspace
|
||||
if let some entry := pkgEntries.find? dep.name then
|
||||
let result ← entry.materialize ws.lakeEnv ws.dir relPkgsDir
|
||||
loadDepPackage result dep.opts leanOpts reconfigure
|
||||
|
||||
@@ -25,7 +25,9 @@ def loadWorkspaceRoot (config : LoadConfig) : LogIO Workspace := do
|
||||
Lean.searchPathRef.set config.lakeEnv.leanSearchPath
|
||||
let (root, env?) ← loadPackageCore "[root]" config
|
||||
let ws : Workspace := {
|
||||
root, lakeEnv := config.lakeEnv
|
||||
root
|
||||
lakeEnv := config.lakeEnv
|
||||
lakeArgs? := config.lakeArgs?
|
||||
moduleFacetConfigs := initModuleFacetConfigs
|
||||
packageFacetConfigs := initPackageFacetConfigs
|
||||
libraryFacetConfigs := initLibraryFacetConfigs
|
||||
@@ -40,19 +42,19 @@ Load a `Workspace` for a Lake package by
|
||||
elaborating its configuration file and resolving its dependencies.
|
||||
If `updateDeps` is true, updates the manifest before resolving dependencies.
|
||||
-/
|
||||
def loadWorkspace (config : LoadConfig) (updateDeps := false) : LogIO Workspace := do
|
||||
let rc := config.reconfigure
|
||||
let leanOpts := config.leanOpts
|
||||
def loadWorkspace (config : LoadConfig) : LoggerIO Workspace := do
|
||||
let {reconfigure, leanOpts, updateDeps, updateToolchain, ..} := config
|
||||
let ws ← loadWorkspaceRoot config
|
||||
if updateDeps then
|
||||
ws.updateAndMaterialize {} leanOpts
|
||||
ws.updateAndMaterialize {} leanOpts updateToolchain
|
||||
else if let some manifest ← Manifest.load? ws.manifestFile then
|
||||
ws.materializeDeps manifest leanOpts rc
|
||||
ws.materializeDeps manifest leanOpts reconfigure
|
||||
else
|
||||
ws.updateAndMaterialize {} leanOpts
|
||||
ws.updateAndMaterialize {} leanOpts updateToolchain
|
||||
|
||||
/-- Updates the manifest for the loaded Lake workspace (see `updateAndMaterialize`). -/
|
||||
def updateManifest (config : LoadConfig) (toUpdate : NameSet := {}) : LogIO Unit := do
|
||||
let leanOpts := config.leanOpts
|
||||
def updateManifest (config : LoadConfig) (toUpdate : NameSet := {})
|
||||
: LoggerIO Unit := do
|
||||
let {leanOpts, updateToolchain, ..} := config
|
||||
let ws ← loadWorkspaceRoot config
|
||||
discard <| ws.updateAndMaterialize toUpdate leanOpts
|
||||
discard <| ws.updateAndMaterialize toUpdate leanOpts updateToolchain
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Mac Malone. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mac Malone
|
||||
-/
|
||||
import Lake.Util.Date
|
||||
|
||||
/-!
|
||||
# TOML Date-Time
|
||||
@@ -22,62 +23,10 @@ optionally left out, creating four distinct variants.
|
||||
|
||||
namespace Lake.Toml
|
||||
|
||||
def lpad (s : String) (c : Char) (len : Nat) : String :=
|
||||
"".pushn c (len - s.length) ++ s
|
||||
|
||||
def rpad (s : String) (c : Char) (len : Nat) : String :=
|
||||
s.pushn c (len - s.length)
|
||||
|
||||
def zpad (n : Nat) (len : Nat) : String :=
|
||||
lpad (toString n) '0' len
|
||||
|
||||
/-- A TOML date (year-month-day). -/
|
||||
structure Date where
|
||||
year : Nat
|
||||
month : Nat
|
||||
day : Nat
|
||||
deriving Inhabited, DecidableEq, Ord
|
||||
|
||||
namespace Date
|
||||
|
||||
abbrev IsLeapYear (y : Nat) : Prop :=
|
||||
y % 4 = 0 ∧ (y % 100 ≠ 0 ∨ y % 400 = 0)
|
||||
|
||||
abbrev IsValidMonth (m : Nat) : Prop :=
|
||||
m ≥ 1 ∧ m ≤ 12
|
||||
|
||||
def maxDay (y m : Nat) : Nat :=
|
||||
if m = 2 then
|
||||
if IsLeapYear y then 29 else 28
|
||||
else if m ≤ 7 then
|
||||
30 + (m % 2)
|
||||
else
|
||||
31 - (m % 2)
|
||||
|
||||
abbrev IsValidDay (y m d : Nat) : Prop :=
|
||||
d ≥ 1 ∧ d ≤ maxDay y m
|
||||
|
||||
def ofValid? (year month day : Nat) : Option Date := do
|
||||
guard (IsValidMonth month ∧ IsValidDay year month day)
|
||||
return {year, month, day}
|
||||
|
||||
def ofString? (t : String) : Option Date := do
|
||||
match t.split (· == '-') with
|
||||
| [y,m,d] =>
|
||||
ofValid? (← y.toNat?) (← m.toNat?) (← d.toNat?)
|
||||
| _ => none
|
||||
|
||||
protected def toString (d : Date) : String :=
|
||||
s!"{zpad d.year 4}-{zpad d.month 2}-{zpad d.day 2}"
|
||||
|
||||
instance : ToString Date := ⟨Date.toString⟩
|
||||
|
||||
end Date
|
||||
|
||||
/--
|
||||
A TOML time (hour:minute:second.fraction).
|
||||
|
||||
We do not represent whole time as seconds to due to the possibility
|
||||
We do not represent the whole time as seconds to due to the possibility
|
||||
of leap seconds in RFC 3339 times.
|
||||
-/
|
||||
structure Time where
|
||||
|
||||
69
src/lake/Lake/Util/Date.lean
Normal file
69
src/lake/Lake/Util/Date.lean
Normal file
@@ -0,0 +1,69 @@
|
||||
/-
|
||||
Copyright (c) 2024 Mac Malone. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mac Malone
|
||||
-/
|
||||
|
||||
/-!
|
||||
# Date
|
||||
|
||||
A year-mont-day date. Used by Lake's TOML parser and its toolchain version
|
||||
parser (for nightlies).
|
||||
-/
|
||||
|
||||
namespace Lake
|
||||
|
||||
def lpad (s : String) (c : Char) (len : Nat) : String :=
|
||||
"".pushn c (len - s.length) ++ s
|
||||
|
||||
def rpad (s : String) (c : Char) (len : Nat) : String :=
|
||||
s.pushn c (len - s.length)
|
||||
|
||||
def zpad (n : Nat) (len : Nat) : String :=
|
||||
lpad (toString n) '0' len
|
||||
|
||||
/-- A date (year-month-day). -/
|
||||
structure Date where
|
||||
year : Nat
|
||||
month : Nat
|
||||
day : Nat
|
||||
deriving Inhabited, DecidableEq, Ord, Repr
|
||||
|
||||
namespace Date
|
||||
|
||||
instance : LT Date := ltOfOrd
|
||||
instance : LE Date := leOfOrd
|
||||
instance : Min Date := minOfLe
|
||||
instance : Max Date := maxOfLe
|
||||
|
||||
abbrev IsLeapYear (y : Nat) : Prop :=
|
||||
y % 4 = 0 ∧ (y % 100 ≠ 0 ∨ y % 400 = 0)
|
||||
|
||||
abbrev IsValidMonth (m : Nat) : Prop :=
|
||||
m ≥ 1 ∧ m ≤ 12
|
||||
|
||||
def maxDay (y m : Nat) : Nat :=
|
||||
if m = 2 then
|
||||
if IsLeapYear y then 29 else 28
|
||||
else if m ≤ 7 then
|
||||
30 + (m % 2)
|
||||
else
|
||||
31 - (m % 2)
|
||||
|
||||
abbrev IsValidDay (y m d : Nat) : Prop :=
|
||||
d ≥ 1 ∧ d ≤ maxDay y m
|
||||
|
||||
def ofValid? (year month day : Nat) : Option Date := do
|
||||
guard (IsValidMonth month ∧ IsValidDay year month day)
|
||||
return {year, month, day}
|
||||
|
||||
def ofString? (t : String) : Option Date := do
|
||||
match t.split (· == '-') with
|
||||
| [y,m,d] =>
|
||||
ofValid? (← y.toNat?) (← m.toNat?) (← d.toNat?)
|
||||
| _ => none
|
||||
|
||||
protected def toString (d : Date) : String :=
|
||||
s!"{zpad d.year 4}-{zpad d.month 2}-{zpad d.day 2}"
|
||||
|
||||
instance : ToString Date := ⟨Date.toString⟩
|
||||
@@ -5,33 +5,39 @@ Authors: Mac Malone
|
||||
-/
|
||||
namespace Lake
|
||||
|
||||
instance (priority := low) [Monad m] [MonadExceptOf PUnit m] : Alternative m where
|
||||
failure := throw ()
|
||||
orElse := tryCatch
|
||||
|
||||
/-- Ensure direct lifts are preferred over indirect ones. -/
|
||||
instance (priority := high) [MonadLift α β] : MonadLiftT α β := ⟨MonadLift.monadLift⟩
|
||||
|
||||
instance [Pure m] : MonadLiftT Id m where
|
||||
instance (priority := low) [Pure m] : MonadLiftT Id m where
|
||||
monadLift act := pure act.run
|
||||
|
||||
instance [Alternative m] : MonadLiftT Option m where
|
||||
instance (priority := low) [Alternative m] : MonadLiftT Option m where
|
||||
monadLift
|
||||
| some a => pure a
|
||||
| none => failure
|
||||
|
||||
instance [Pure m] [MonadExceptOf ε m] : MonadLiftT (Except ε) m where
|
||||
instance (priority := low) [Pure m] [MonadExceptOf ε m] : MonadLiftT (Except ε) m where
|
||||
monadLift
|
||||
| .ok a => pure a
|
||||
| .error e => throw e
|
||||
|
||||
instance [Bind m] [MonadReaderOf ρ m] [MonadLiftT n m] : MonadLiftT (ReaderT ρ n) m where
|
||||
-- Remark: not necessarily optimal; uses context non-linearly
|
||||
instance (priority := low) [Bind m] [MonadReaderOf ρ m] [MonadLiftT n m] : MonadLiftT (ReaderT ρ n) m where
|
||||
monadLift act := do act (← read)
|
||||
|
||||
instance [Monad m] [MonadStateOf σ m] [MonadLiftT n m] : MonadLiftT (StateT σ n) m where
|
||||
-- Remark: not necessarily optimal; uses state non-linearly
|
||||
instance (priority := low) [Monad m] [MonadStateOf σ m] [MonadLiftT n m] : MonadLiftT (StateT σ n) m where
|
||||
monadLift act := do let (a, s) ← act (← get); set s; pure a
|
||||
|
||||
instance [Monad m] [Alternative m] [MonadLiftT n m] : MonadLiftT (OptionT n) m where
|
||||
instance (priority := low) [Monad m] [Alternative m] [MonadLiftT n m] : MonadLiftT (OptionT n) m where
|
||||
monadLift act := act.run >>= liftM
|
||||
|
||||
instance [Monad m] [MonadExceptOf ε m] [MonadLiftT n m] : MonadLiftT (ExceptT ε n) m where
|
||||
instance (priority := low) [Monad m] [MonadExceptOf ε m] [MonadLiftT n m] : MonadLiftT (ExceptT ε n) m where
|
||||
monadLift act := act.run >>= liftM
|
||||
|
||||
instance [Monad m] [MonadExceptOf ε m] [MonadLiftT BaseIO m] : MonadLiftT (EIO ε) m where
|
||||
instance (priority := low) [Monad m] [MonadExceptOf ε m] [MonadLiftT BaseIO m] : MonadLiftT (EIO ε) m where
|
||||
monadLift act := act.toBaseIO >>= liftM
|
||||
|
||||
@@ -5,6 +5,7 @@ Authors: Mac Malone
|
||||
-/
|
||||
import Lake.Util.Error
|
||||
import Lake.Util.EStateT
|
||||
import Lake.Util.Lift
|
||||
import Lean.Data.Json
|
||||
import Lean.Message
|
||||
|
||||
@@ -195,6 +196,9 @@ abbrev stream [MonadLiftT BaseIO m]
|
||||
(out : IO.FS.Stream) (minLv := LogLevel.info) (useAnsi := false)
|
||||
: MonadLog m where logEntry e := logToStream e out minLv useAnsi
|
||||
|
||||
@[inline] def error [Alternative m] [MonadLog m] (msg : String) : m α :=
|
||||
logError msg *> failure
|
||||
|
||||
end MonadLog
|
||||
|
||||
def OutStream.logEntry
|
||||
@@ -404,7 +408,7 @@ from an `ELogT` (e.g., `LogIO`).
|
||||
(msg : String)
|
||||
: m α := errorWithLog (logError msg)
|
||||
|
||||
/-- `Alternative` instance for monads with `Log` state and `Log.Pos` errors. -/
|
||||
/-- `MonadError` instance for monads with `Log` state and `Log.Pos` errors. -/
|
||||
abbrev ELog.monadError
|
||||
[Monad m] [MonadLog m] [MonadStateOf Log m] [MonadExceptOf Log.Pos m]
|
||||
: MonadError m := ⟨ELog.error⟩
|
||||
@@ -505,7 +509,7 @@ abbrev run?' [Functor m] (self : ELogT m α) (log : Log := {}) : m (Option α) :
|
||||
Run `self` with the log taken from the state of the monad `n`,
|
||||
|
||||
**Warning:** If lifting `self` from `m` to `n` fails, the log will be lost.
|
||||
Thus, this is best used when the lift cannot fail. Note excludes the
|
||||
Thus, this is best used when the lift cannot fail. This excludes the
|
||||
native log position failure of `ELogT`, which are lifted safely.
|
||||
-/
|
||||
@[inline] def takeAndRun
|
||||
@@ -545,8 +549,6 @@ instance : MonadLift IO LogIO := ⟨MonadError.runIO⟩
|
||||
|
||||
namespace LogIO
|
||||
|
||||
@[deprecated ELogT.run? (since := "2024-05-18")] abbrev captureLog := @ELogT.run?
|
||||
|
||||
/--
|
||||
Runs a `LogIO` action in `BaseIO`.
|
||||
Prints log entries of at least `minLv` to `out`.
|
||||
@@ -563,4 +565,46 @@ where
|
||||
replay (log : Log) (logger : MonadLog BaseIO) : BaseIO Unit :=
|
||||
log.replay (logger := logger)
|
||||
|
||||
-- deprecated 2024-05-18, reversed 2024-10-18
|
||||
abbrev captureLog := @ELogT.run?
|
||||
|
||||
end LogIO
|
||||
|
||||
/--
|
||||
A monad equipped with a log function and the ability to perform I/O.
|
||||
Unlike `LogIO`, log entries are not retained by the monad but instead eagerly
|
||||
passed to the log function.
|
||||
-/
|
||||
abbrev LoggerIO := MonadLogT BaseIO (EIO PUnit)
|
||||
|
||||
instance : MonadError LoggerIO := ⟨MonadLog.error⟩
|
||||
instance : MonadLift IO LoggerIO := ⟨MonadError.runIO⟩
|
||||
instance : MonadLift LogIO LoggerIO := ⟨ELogT.replayLog⟩
|
||||
|
||||
namespace LoggerIO
|
||||
|
||||
/--
|
||||
Runs a `LoggerIO` action in `BaseIO`.
|
||||
Prints log entries of at least `minLv` to `out`.
|
||||
-/
|
||||
@[inline] def toBaseIO
|
||||
(self : LoggerIO α)
|
||||
(minLv := LogLevel.info) (ansiMode := AnsiMode.auto) (out := OutStream.stderr)
|
||||
: BaseIO (Option α) := do
|
||||
(·.toOption) <$> (self.run (← out.getLogger minLv ansiMode)).toBaseIO
|
||||
|
||||
def captureLog (self : LoggerIO α) : BaseIO (Option α × Log) := do
|
||||
let ref ← IO.mkRef ({} : Log)
|
||||
let e ← self.run ⟨fun e => ref.modify (·.push e)⟩ |>.toBaseIO
|
||||
return (e.toOption, ← ref.get)
|
||||
|
||||
-- For parity with `LogIO.run?`
|
||||
abbrev run? := @captureLog
|
||||
|
||||
-- For parity with `LogIO.run?'`
|
||||
@[inline] def run?'
|
||||
(self : LoggerIO α) (logger : LogEntry → BaseIO PUnit := fun _ => pure ())
|
||||
: BaseIO (Option α) := do
|
||||
(·.toOption) <$> (self.run ⟨logger⟩).toBaseIO
|
||||
|
||||
end LoggerIO
|
||||
|
||||
@@ -88,3 +88,12 @@ where
|
||||
log.replay (logger := logger)
|
||||
|
||||
instance (priority := low) : MonadLift LogIO MainM := ⟨runLogIO⟩
|
||||
|
||||
@[inline] def runLoggerIO (x : LoggerIO α)
|
||||
(minLv := LogLevel.info) (ansiMode := AnsiMode.auto) (out := OutStream.stderr)
|
||||
: MainM α := do
|
||||
let some a ← x.run (← out.getLogger minLv ansiMode) |>.toBaseIO
|
||||
| exit 1
|
||||
return a
|
||||
|
||||
instance (priority := low) : MonadLift LoggerIO MainM := ⟨runLoggerIO⟩
|
||||
|
||||
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mac Malone
|
||||
-/
|
||||
import Lean.Elab.Eval
|
||||
import Lake.Util.Date
|
||||
|
||||
/-! # Version
|
||||
|
||||
@@ -11,7 +12,7 @@ This module contains useful definitions for manipulating versions.
|
||||
It also defines a `v!"<ver>"` syntax for version literals.
|
||||
-/
|
||||
|
||||
open Lean
|
||||
open System Lean
|
||||
|
||||
namespace Lake
|
||||
|
||||
@@ -117,6 +118,112 @@ instance : ToExpr StdVer where
|
||||
#[toExpr ver.toSemVerCore, toExpr ver.specialDescr]
|
||||
toTypeExpr := mkConst ``StdVer
|
||||
|
||||
/-- A Lean toolchain version. -/
|
||||
inductive ToolchainVer
|
||||
| release (ver : LeanVer)
|
||||
| nightly (date : Date)
|
||||
| pr (no : Nat)
|
||||
| other (name : String)
|
||||
deriving Repr, DecidableEq
|
||||
|
||||
instance : Coe LeanVer ToolchainVer := ⟨ToolchainVer.release⟩
|
||||
|
||||
def ToolchainVer.defaultOrigin := "leanprover/lean4"
|
||||
def ToolchainVer.prOrigin := "leanprover/lean4-pr-releases"
|
||||
|
||||
def ToolchainVer.ofString (ver : String) : ToolchainVer := Id.run do
|
||||
let colonPos := ver.posOf ':'
|
||||
let (origin, tag) :=
|
||||
if h : colonPos < ver.endPos then
|
||||
let pos := ver.next' colonPos (by simp_all [h, String.endPos, String.atEnd])
|
||||
(ver.extract 0 colonPos, ver.extract pos ver.endPos)
|
||||
else
|
||||
("", ver)
|
||||
if tag.startsWith "v" then
|
||||
if let .ok ver := StdVer.parse (tag.drop 1) then
|
||||
if origin.isEmpty || origin == defaultOrigin then
|
||||
return .release ver
|
||||
return .other ver
|
||||
else if tag.startsWith "nightly-" then
|
||||
if let some date := Date.ofString? (tag.drop "nightly-".length) then
|
||||
if origin.isEmpty || origin == defaultOrigin then
|
||||
return .nightly date
|
||||
else if tag.startsWith "pr-release-" then
|
||||
if let some n := (tag.drop "pr-release-".length).toNat? then
|
||||
if origin.isEmpty || origin == prOrigin then
|
||||
return .pr n
|
||||
else
|
||||
if let .ok ver := StdVer.parse ver then
|
||||
if origin.isEmpty || origin == defaultOrigin then
|
||||
return .release ver
|
||||
return .other ver
|
||||
|
||||
/-- Parse a toolchain from a `lean-toolchain` file. -/
|
||||
def ToolchainVer.ofFile? (toolchainFile : FilePath) : IO (Option ToolchainVer) := do
|
||||
try
|
||||
let toolchainString ← IO.FS.readFile toolchainFile
|
||||
return some <| ToolchainVer.ofString toolchainString.trim
|
||||
catch
|
||||
| .noFileOrDirectory .. =>
|
||||
return none
|
||||
| e => throw e
|
||||
|
||||
/-- The `elan` toolchain file name (i.e., `lean-toolchain`). -/
|
||||
def toolchainFileName : FilePath := "lean-toolchain"
|
||||
|
||||
/-- Parse a toolchain from the `lean-toolchain` file of the directory `dir`. -/
|
||||
@[inline] def ToolchainVer.ofDir? (dir : FilePath) : IO (Option ToolchainVer) :=
|
||||
ToolchainVer.ofFile? (dir / toolchainFileName)
|
||||
|
||||
protected def ToolchainVer.toString (ver : ToolchainVer) : String :=
|
||||
match ver with
|
||||
| .release ver => s!"{defaultOrigin}:v{ver}"
|
||||
| .nightly date => s!"{defaultOrigin}:nightly-{date}"
|
||||
| .pr n => s!"{prOrigin}:pr-release-{n}"
|
||||
| .other s => s
|
||||
|
||||
instance : ToString ToolchainVer := ⟨ToolchainVer.toString⟩
|
||||
instance : ToJson ToolchainVer := ⟨(·.toString)⟩
|
||||
instance : FromJson ToolchainVer := ⟨(ToolchainVer.ofString <$> fromJson? ·)⟩
|
||||
|
||||
protected def ToolchainVer.lt (a b : ToolchainVer) : Prop :=
|
||||
match a, b with
|
||||
| .release v1, .release v2 => v1 < v2
|
||||
| .nightly d1, .nightly d2 => d1 < d2
|
||||
| _, _ => False
|
||||
|
||||
instance : LT ToolchainVer := ⟨ToolchainVer.lt⟩
|
||||
|
||||
instance ToolchainVer.decLt (a b : ToolchainVer) : Decidable (a < b) :=
|
||||
match a, b with
|
||||
| .release v1, .release v2 => inferInstanceAs (Decidable (v1 < v2))
|
||||
| .nightly d1, .nightly d2 => inferInstanceAs (Decidable (d1 < d2))
|
||||
| .release _, .pr _ | .release _, .nightly _ | .release _, .other _
|
||||
| .nightly _, .release _ | .nightly _, .pr _ | .nightly _, .other _
|
||||
| .pr _, _ | .other _, _ => .isFalse (by simp [LT.lt, ToolchainVer.lt])
|
||||
|
||||
protected def ToolchainVer.le (a b : ToolchainVer) : Prop :=
|
||||
match a, b with
|
||||
| .release v1, .release v2 => v1 ≤ v2
|
||||
| .nightly d1, .nightly d2 => d1 ≤ d2
|
||||
| .pr n1, .pr n2 => n1 = n2
|
||||
| .other v1, .other v2 => v1 = v2
|
||||
| _, _ => False
|
||||
|
||||
instance : LE ToolchainVer := ⟨ToolchainVer.le⟩
|
||||
|
||||
instance ToolchainVer.decLe (a b : ToolchainVer) : Decidable (a ≤ b) :=
|
||||
match a, b with
|
||||
| .release v1, .release v2 => inferInstanceAs (Decidable (v1 ≤ v2))
|
||||
| .nightly d1, .nightly d2 => inferInstanceAs (Decidable (d1 ≤ d2))
|
||||
| .pr n1, .pr n2 => inferInstanceAs (Decidable (n1 = n2))
|
||||
| .other v1, .other v2 => inferInstanceAs (Decidable (v1 = v2))
|
||||
| .release _, .pr _ | .release _, .nightly _ | .release _, .other _
|
||||
| .nightly _, .release _ | .nightly _, .pr _ | .nightly _, other _
|
||||
| .pr _, .release _ | .pr _, .nightly _ | .pr _, .other _
|
||||
| .other _, .release _ | .other _, .nightly _ | .other _, .pr _ =>
|
||||
.isFalse (by simp [LE.le, ToolchainVer.le])
|
||||
|
||||
/-! ## Version Literals
|
||||
|
||||
Defines the `v!"<ver>"` syntax for version literals.
|
||||
@@ -134,6 +241,7 @@ export DecodeVersion (decodeVersion)
|
||||
|
||||
instance : DecodeVersion SemVerCore := ⟨SemVerCore.parse⟩
|
||||
@[default_instance] instance : DecodeVersion StdVer := ⟨StdVer.parse⟩
|
||||
instance : DecodeVersion ToolchainVer := ⟨(pure <| ToolchainVer.ofString ·)⟩
|
||||
|
||||
private def toResultExpr [ToExpr α] (x : Except String α) : Except String Expr :=
|
||||
Functor.map toExpr x
|
||||
|
||||
@@ -3,31 +3,31 @@
|
||||
"packages":
|
||||
[{"type": "path",
|
||||
"scope": "",
|
||||
"name": "root",
|
||||
"name": "foo",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inherited": true,
|
||||
"dir": "./../foo/../a/../root",
|
||||
"configFile": "lakefile.lean"},
|
||||
{"type": "path",
|
||||
"scope": "",
|
||||
"name": "a",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inherited": true,
|
||||
"dir": "./../foo/../a",
|
||||
"inherited": false,
|
||||
"dir": "./../foo",
|
||||
"configFile": "lakefile.lean"},
|
||||
{"type": "path",
|
||||
"scope": "",
|
||||
"name": "b",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inherited": true,
|
||||
"dir": "./../foo/../b",
|
||||
"dir": "./../foo/./../b",
|
||||
"configFile": "lakefile.lean"},
|
||||
{"type": "path",
|
||||
"scope": "",
|
||||
"name": "foo",
|
||||
"name": "a",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inherited": false,
|
||||
"dir": "./../foo",
|
||||
"inherited": true,
|
||||
"dir": "./../foo/./../a",
|
||||
"configFile": "lakefile.lean"},
|
||||
{"type": "path",
|
||||
"scope": "",
|
||||
"name": "root",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inherited": true,
|
||||
"dir": "./../foo/./../b/./../root",
|
||||
"configFile": "lakefile.lean"}],
|
||||
"name": "bar",
|
||||
"lakeDir": ".lake"}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
dep/hello
|
||||
scripts/say-goodbye
|
||||
scripts/greet
|
||||
dep/hello
|
||||
Hello, world!
|
||||
Hello, me!
|
||||
Hello, --me!
|
||||
@@ -16,8 +16,8 @@ Hello from Dep!
|
||||
Goodbye!
|
||||
error: unknown script nonexistent
|
||||
error: unknown script nonexistent
|
||||
dep/hello
|
||||
scripts/say-goodbye
|
||||
scripts/greet
|
||||
dep/hello
|
||||
Hello, world!
|
||||
Goodbye!
|
||||
|
||||
@@ -17,6 +17,7 @@ fi
|
||||
mkdir hello
|
||||
pushd hello
|
||||
$LAKE init hello
|
||||
rm -f lean-toolchain
|
||||
$LAKE update
|
||||
git init
|
||||
git checkout -b master
|
||||
@@ -34,7 +35,7 @@ cd test
|
||||
LAKE_PKG_URL_MAP=$HELLO_MAP $LAKE update 2>&1 | grep --color "file://"
|
||||
# test that a second `lake update` is a no-op (with URLs)
|
||||
# see https://github.com/leanprover/lean4/commit/6176fdba9e5a888225a23e5d558a005e0d1eb2f6#r125905901
|
||||
LAKE_PKG_URL_MAP=$HELLO_MAP $LAKE update 2>&1 | diff - /dev/null
|
||||
LAKE_PKG_URL_MAP=$HELLO_MAP $LAKE update --keep-toolchain 2>&1 | diff - /dev/null
|
||||
rm -rf .lake/packages
|
||||
|
||||
# Test that Lake produces no warnings on a `lake build` after a `lake update`
|
||||
@@ -42,7 +43,7 @@ rm -rf .lake/packages
|
||||
|
||||
$LAKE update
|
||||
# test that a second `lake update` is a no-op (with file paths)
|
||||
$LAKE update 2>&1 | diff - /dev/null
|
||||
$LAKE update --keep-toolchain 2>&1 | diff - /dev/null
|
||||
test -d .lake/packages/hello
|
||||
# test that Lake produces no warnings
|
||||
$LAKE build 3>&1 1>&2 2>&3 | diff - /dev/null
|
||||
|
||||
@@ -75,8 +75,8 @@ pushd d
|
||||
git init
|
||||
git checkout -b master
|
||||
cat >>lakefile.lean <<EOF
|
||||
require b from git "../b" @ "master"
|
||||
require c from git "../c" @ "master"
|
||||
require b from git "../b" @ "master"
|
||||
EOF
|
||||
# make sure we pick up the version from b's manifest (a@1)
|
||||
$LAKE update -v 2>&1 | grep --color 'first commit in a'
|
||||
@@ -129,13 +129,20 @@ $LAKE update a -v
|
||||
git commit -am 'second commit in b'
|
||||
popd
|
||||
pushd a
|
||||
# a@4
|
||||
# a@4/main
|
||||
sed_i 's/third commit/fourth commit/' A.lean
|
||||
git commit -am 'fourth commit in a'
|
||||
popd
|
||||
pushd c
|
||||
# c@2
|
||||
echo '-- second commit in c' >>C.lean
|
||||
git commit -am 'second commit in c'
|
||||
popd
|
||||
pushd d
|
||||
# d: b@1 -> b@2 => a@1 -> a@3
|
||||
$LAKE update b -v
|
||||
# test that Lake does not update c
|
||||
grep --color 'second commit in c' .lake/packages/c/C.lean && exit 1 || true
|
||||
# test 119: pickup a@3 and not a@4
|
||||
grep --color 'third commit in a' .lake/packages/a/A.lean
|
||||
# test the removal of `c` from the manifest
|
||||
|
||||
1
src/lake/tests/env/test.sh
vendored
1
src/lake/tests/env/test.sh
vendored
@@ -13,6 +13,7 @@ $LAKE env | grep ".*=.*"
|
||||
# NOTE: `printenv` exits with code 1 if the variable is not set
|
||||
$LAKE env printenv LAKE
|
||||
$LAKE env printenv LAKE_HOME
|
||||
$LAKE env printenv LEAN
|
||||
$LAKE env printenv LEAN_GITHASH
|
||||
$LAKE env printenv LEAN_SYSROOT
|
||||
$LAKE env printenv LEAN_AR | grep --color ar
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
{"version": "1.1.0",
|
||||
"packagesDir": ".lake/packages",
|
||||
"packages":
|
||||
[{"type": "path",
|
||||
"scope": "",
|
||||
"name": "foo",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inherited": false,
|
||||
"dir": "./foo",
|
||||
"configFile": "lakefile.lean"},
|
||||
{"url": "bar",
|
||||
[{"url": "bar",
|
||||
"type": "git",
|
||||
"subDir": null,
|
||||
"scope": "foo",
|
||||
@@ -17,6 +10,13 @@
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": null,
|
||||
"inherited": false,
|
||||
"configFile": "lakefile.lean"},
|
||||
{"type": "path",
|
||||
"scope": "",
|
||||
"name": "foo",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inherited": false,
|
||||
"dir": "./foo",
|
||||
"configFile": "lakefile.lean"}],
|
||||
"name": "«foo-bar»",
|
||||
"lakeDir": ".lake"}
|
||||
|
||||
@@ -11,13 +11,13 @@ export ELAN_TOOLCHAIN=test
|
||||
grep --color "error: bogus/bogus: could not materialize package: dependency has no explicit source and was not found on Reservoir"
|
||||
|
||||
./clean.sh
|
||||
$LAKE -f git.toml update
|
||||
$LAKE -f git.toml update --keep-toolchain
|
||||
# Test that barrels are not fetched for non-Reservoir dependencies
|
||||
$LAKE -v -f git.toml build @Cli:extraDep |
|
||||
grep --color "Cli:optBarrel" && exit 1 || true
|
||||
|
||||
./clean.sh
|
||||
$LAKE -f barrel.lean update
|
||||
$LAKE -f barrel.lean update --keep-toolchain
|
||||
# Test that a barrel is not fetched for an unbuilt dependency
|
||||
$LAKE -v -f barrel.lean build @test:extraDep |
|
||||
grep --color "Cli:optBarrel" && exit 1 || true
|
||||
@@ -53,11 +53,11 @@ LEAN_GITHASH=ec3042d94bd11a42430f9e14d39e26b1f880f99b \
|
||||
$LAKE -f barrel.lean build Cli --no-build
|
||||
|
||||
./clean.sh
|
||||
$LAKE -f require.lean update -v
|
||||
$LAKE -f require.lean update -v --keep-toolchain
|
||||
test -d .lake/packages/doc-gen4
|
||||
$LAKE -f require.lean resolve-deps # validate manifest
|
||||
|
||||
./clean.sh
|
||||
$LAKE -f require.toml update v
|
||||
$LAKE -f require.toml update -v --keep-toolchain
|
||||
test -d .lake/packages/doc-gen4
|
||||
$LAKE -f require.toml resolve-deps # validate manifest
|
||||
|
||||
@@ -4,6 +4,7 @@ open Lake DSL
|
||||
package bar where
|
||||
moreLeanArgs := #["-DmaxHeartbeats=888000"]
|
||||
|
||||
require baz from ".." / "baz"
|
||||
require leaf from ".." / "leaf" with NameMap.empty.insert `val "888000"
|
||||
|
||||
lean_lib X
|
||||
|
||||
0
src/lake/tests/order/baz/X.lean
Normal file
0
src/lake/tests/order/baz/X.lean
Normal file
7
src/lake/tests/order/baz/lakefile.lean
Normal file
7
src/lake/tests/order/baz/lakefile.lean
Normal file
@@ -0,0 +1,7 @@
|
||||
import Lake
|
||||
open Lake DSL
|
||||
|
||||
package baz where
|
||||
moreLeanArgs := #["-DmaxHeartbeats=999000"]
|
||||
|
||||
lean_lib X
|
||||
@@ -1,3 +1,3 @@
|
||||
rm -rf .lake foo/.lake bar/.lake leaf/.lake
|
||||
rm -f lake-manifest.json foo/lake-manifest.json bar/lake-manifest.json leaf/lake-manifest.json
|
||||
rm -rf .lake foo/.lake bar/.lake baz/.lake leaf/.lake
|
||||
rm -f lake-manifest.json foo/lake-manifest.json bar/lake-manifest.json baz/lake-manifest.json leaf/lake-manifest.json
|
||||
rm -f lake-manifest-1.json
|
||||
|
||||
@@ -10,13 +10,13 @@ LAKE=${LAKE:-../../.lake/build/bin/lake}
|
||||
# Later packages and libraries in the dependency tree shadow earlier ones.
|
||||
# https://github.com/leanprover/lean4/issues/2548
|
||||
|
||||
$LAKE update
|
||||
$LAKE update -v
|
||||
$LAKE build +A -v | grep --color 222000
|
||||
$LAKE build +A.B -v | grep --color 333000
|
||||
$LAKE build +A.B.C -v | grep --color 333000
|
||||
$LAKE build +X -v | grep --color 888000
|
||||
$LAKE build +Y -v | grep --color 666000
|
||||
$LAKE build +Z -v | grep --color 666000
|
||||
$LAKE build +X -v | grep --color 888000 # bar
|
||||
$LAKE build +Y -v | grep --color 666000 # order
|
||||
$LAKE build +Z -v | grep --color 666000 # leaf from order
|
||||
$LAKE exe Y | grep --color root
|
||||
|
||||
# Tests that `lake update` does not reorder packages in the manifest
|
||||
|
||||
1
src/lake/tests/toolchain/.gitignore
vendored
1
src/lake/tests/toolchain/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
/foo
|
||||
lean-toolchain
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
rm -rf foo
|
||||
rm -f lake-manifest.json lean-toolchain
|
||||
|
||||
6
src/lake/tests/toolchain/lakefile.lean
Normal file
6
src/lake/tests/toolchain/lakefile.lean
Normal file
@@ -0,0 +1,6 @@
|
||||
import Lake
|
||||
open System Lake DSL
|
||||
|
||||
package test
|
||||
|
||||
require foo from "foo"
|
||||
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
|
||||
# Tests that Lake rebuilds when toolchain changes
|
||||
# See https://github.com/leanprover/lake/issues/62
|
||||
# Requires Elan to download a toolchain
|
||||
LAKE=${LAKE:-../../../.lake/build/bin/lake}
|
||||
|
||||
# Tests which require Elan to download a toolchain
|
||||
|
||||
# skip if no elan found
|
||||
if ! command -v elan > /dev/null; then
|
||||
@@ -11,9 +11,20 @@ if ! command -v elan > /dev/null; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Test that Lake rebuilds when toolchain changes
|
||||
# See https://github.com/leanprover/lake/issues/62
|
||||
|
||||
TOOLCHAIN=leanprover/lean4:v4.0.0
|
||||
./clean.sh
|
||||
elan run --install leanprover/lean4:v4.0.0 lake new foo
|
||||
cd foo
|
||||
elan run leanprover/lean4:v4.0.0 lake build +Foo:olean -v | grep --color Foo.olean
|
||||
rm lean-toolchain
|
||||
${LAKE:-../../../.lake/build/bin/lake} build -v | grep --color Foo.olean
|
||||
elan run --install $TOOLCHAIN lake new foo
|
||||
pushd foo
|
||||
elan run $TOOLCHAIN lake build +Foo:olean -v | grep --color Foo.olean
|
||||
rm lean-toolchain # switch to Lake under test
|
||||
$LAKE build -v | grep --color Foo.olean
|
||||
popd
|
||||
|
||||
# Test Lake runs under the new toolchain after Lake updates it
|
||||
rm -f foo/lake-manifest.json
|
||||
echo $TOOLCHAIN > foo/lean-toolchain
|
||||
$LAKE update
|
||||
grep --color -F '"version": 5' lake-manifest.json
|
||||
|
||||
1
src/lake/tests/updateToolchain/.gitignore
vendored
Normal file
1
src/lake/tests/updateToolchain/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
lean-toolchain
|
||||
1
src/lake/tests/updateToolchain/a/lakefile.toml
Normal file
1
src/lake/tests/updateToolchain/a/lakefile.toml
Normal file
@@ -0,0 +1 @@
|
||||
name = "a"
|
||||
1
src/lake/tests/updateToolchain/b/lakefile.toml
Normal file
1
src/lake/tests/updateToolchain/b/lakefile.toml
Normal file
@@ -0,0 +1 @@
|
||||
name = "b"
|
||||
1
src/lake/tests/updateToolchain/clean.sh
Executable file
1
src/lake/tests/updateToolchain/clean.sh
Executable file
@@ -0,0 +1 @@
|
||||
rm -f lean-toolchain a/lean-toolchain b/lean-toolchain
|
||||
9
src/lake/tests/updateToolchain/lakefile.toml
Normal file
9
src/lake/tests/updateToolchain/lakefile.toml
Normal file
@@ -0,0 +1,9 @@
|
||||
name = "test"
|
||||
|
||||
[[require]]
|
||||
name = "a"
|
||||
path = "a"
|
||||
|
||||
[[require]]
|
||||
name = "b"
|
||||
path = "b"
|
||||
35
src/lake/tests/updateToolchain/test.lean
Normal file
35
src/lake/tests/updateToolchain/test.lean
Normal file
@@ -0,0 +1,35 @@
|
||||
import Lake.Util.Version
|
||||
|
||||
open Lake
|
||||
|
||||
def checkParse (tc : String) :=
|
||||
IO.println <| repr <| ToolchainVer.ofString tc
|
||||
|
||||
def checkLt (tc1 tc2 : String) :=
|
||||
IO.println <| decide <| ToolchainVer.ofString tc1 < ToolchainVer.ofString tc2
|
||||
|
||||
def test := do
|
||||
IO.println ""
|
||||
checkParse "leanprover/lean4:v4.13.0-rc1"
|
||||
checkParse "leanprover/lean4:nightly-2024-09-15"
|
||||
checkParse "leanprover/lean4-pr-releases:pr-release-101"
|
||||
checkParse "leanprover/lean:v4.1.0"
|
||||
checkParse "4.12.0"
|
||||
checkLt "4.6.0-rc1" "v4.6.0"
|
||||
checkLt "4.12.0" "leanprover/lean4:v4.13.0-rc1"
|
||||
checkLt "nightly-2024-09-08" "nightly-2024-10-09"
|
||||
checkLt "nightly-2024-09-08" "4.0.0"
|
||||
|
||||
/--
|
||||
info:
|
||||
Lake.ToolchainVer.release { toSemVerCore := { major := 4, minor := 13, patch := 0 }, specialDescr := "rc1" }
|
||||
Lake.ToolchainVer.nightly { year := 2024, month := 9, day := 15 }
|
||||
Lake.ToolchainVer.pr 101
|
||||
Lake.ToolchainVer.other "leanprover/lean:v4.1.0"
|
||||
Lake.ToolchainVer.release { toSemVerCore := { major := 4, minor := 12, patch := 0 }, specialDescr := "" }
|
||||
true
|
||||
true
|
||||
true
|
||||
false
|
||||
-/
|
||||
#guard_msgs in #eval test
|
||||
68
src/lake/tests/updateToolchain/test.sh
Executable file
68
src/lake/tests/updateToolchain/test.sh
Executable file
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
|
||||
LAKE=${LAKE:-../../.lake/build/bin/lake}
|
||||
|
||||
# Ensure Lake thinks there is a elan environment configured
|
||||
export ELAN_HOME=
|
||||
|
||||
# Tests the toolchain update functionality of `lake update`
|
||||
|
||||
RESTART_CODE=4
|
||||
|
||||
test_update(){
|
||||
ELAN=true $LAKE update 2>&1 | grep --color "updating toolchain to '$1'"
|
||||
cat lean-toolchain | diff - <(echo -n "$1")
|
||||
}
|
||||
|
||||
# Test toolchain version API
|
||||
$LAKE lean test.lean
|
||||
|
||||
# Test no toolchain information
|
||||
./clean.sh
|
||||
$LAKE update 2>&1 | grep --color "toolchain not updated; no toolchain information found"
|
||||
|
||||
# Test a single unknown candidate
|
||||
./clean.sh
|
||||
echo lean-a > a/lean-toolchain
|
||||
test_update lean-a
|
||||
|
||||
# Test a single known (PR) candidate
|
||||
./clean.sh
|
||||
echo pr-release-101 > a/lean-toolchain
|
||||
test_update leanprover/lean4-pr-releases:pr-release-101
|
||||
|
||||
# Test release comparison
|
||||
./clean.sh
|
||||
echo v4.4.0 > a/lean-toolchain
|
||||
echo v4.8.0 > b/lean-toolchain
|
||||
test_update leanprover/lean4:v4.8.0
|
||||
|
||||
# Test nightly comparison
|
||||
./clean.sh
|
||||
echo nightly-2024-10-01 > a/lean-toolchain
|
||||
echo nightly-2024-01-10 > b/lean-toolchain
|
||||
test_update leanprover/lean4:nightly-2024-10-01
|
||||
|
||||
# Test up-to-date root
|
||||
./clean.sh
|
||||
echo v4.4.0 > a/lean-toolchain
|
||||
echo v4.8.0 > b/lean-toolchain
|
||||
echo v4.10.0 > lean-toolchain
|
||||
$LAKE update 2>&1 | grep --color "toolchain not updated; already up-to-date"
|
||||
|
||||
# Test multiple candidates
|
||||
./clean.sh
|
||||
echo lean-a > a/lean-toolchain
|
||||
echo lean-b > b/lean-toolchain
|
||||
$LAKE update 2>&1 | grep --color "toolchain not updated; multiple toolchain candidates"
|
||||
|
||||
# Test manual restart
|
||||
./clean.sh
|
||||
echo lean-a > a/lean-toolchain
|
||||
ELAN= $LAKE update 2>&1 && exit 1 || [ $? = $RESTART_CODE ]
|
||||
|
||||
# Test elan restart
|
||||
./clean.sh
|
||||
echo lean-a > a/lean-toolchain
|
||||
ELAN=echo $LAKE update | grep --color "run --install lean-a lake update"
|
||||
@@ -61,7 +61,9 @@ struct olean_header {
|
||||
0b0;
|
||||
#endif
|
||||
// 33 bytes: Lean version string, padded with '\0' to the right
|
||||
// e.g. "4.12.0-nightly-2024-10-18". May not be null-terminated.
|
||||
// e.g. "4.12.0-nightly-2024-10-18". Other suffixes after the version
|
||||
// triple currently in use are `-rcN` for some `N` and `-pre` for any
|
||||
// other non-release commit. Not necessarily null-terminated.
|
||||
char lean_version[33];
|
||||
// 81b008650766442a0dfa9faa796e4588c9d7d3a1
|
||||
// 40 bytes: build githash, padded with `\0` to the right
|
||||
|
||||
@@ -861,11 +861,7 @@ void initialize_library_util() {
|
||||
|
||||
sstream out;
|
||||
|
||||
out << LEAN_VERSION_MAJOR << "."
|
||||
<< LEAN_VERSION_MINOR << "." << LEAN_VERSION_PATCH;
|
||||
if (std::strlen(LEAN_SPECIAL_VERSION_DESC) > 0) {
|
||||
out << "-" << LEAN_SPECIAL_VERSION_DESC;
|
||||
}
|
||||
out << LEAN_VERSION_STRING;
|
||||
g_short_version_string = new std::string(out.str());
|
||||
if (std::strlen(LEAN_PLATFORM_TARGET) > 0) {
|
||||
out << ", " << LEAN_PLATFORM_TARGET;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user