mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-20 20:04:23 +00:00
Compare commits
31 Commits
array_clea
...
array_clea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
135872c136 | ||
|
|
8dd2aa529a | ||
|
|
def81076de | ||
|
|
46f1335b80 | ||
|
|
682173d7c0 | ||
|
|
26df545598 | ||
|
|
11ae8bae42 | ||
|
|
a167860e3b | ||
|
|
cc76496050 | ||
|
|
41b35baea2 | ||
|
|
a6243f6076 | ||
|
|
fd15d8f9ed | ||
|
|
1d66ff8231 | ||
|
|
51ab162a5a | ||
|
|
41797a78c3 | ||
|
|
d6a7eb3987 | ||
|
|
fc5e3cc66e | ||
|
|
372f344155 | ||
|
|
f2ac0d03c6 | ||
|
|
08d8a0873e | ||
|
|
68b0471de9 | ||
|
|
3a34a8e0d1 | ||
|
|
6fa75e346a | ||
|
|
2669fb525f | ||
|
|
8632b79023 | ||
|
|
e8970463d1 | ||
|
|
69e8cd3d8a | ||
|
|
565ac23b78 | ||
|
|
c1750f4316 | ||
|
|
092c87a70f | ||
|
|
b8fc6c593a |
8
.github/workflows/check-prelude.yml
vendored
8
.github/workflows/check-prelude.yml
vendored
@@ -11,7 +11,9 @@ jobs:
|
||||
with:
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
sparse-checkout: src/Lean
|
||||
sparse-checkout: |
|
||||
src/Lean
|
||||
src/Std
|
||||
- name: Check Prelude
|
||||
run: |
|
||||
failed_files=""
|
||||
@@ -19,8 +21,8 @@ jobs:
|
||||
if ! grep -q "^prelude$" "$file"; then
|
||||
failed_files="$failed_files$file\n"
|
||||
fi
|
||||
done < <(find src/Lean -name '*.lean' -print0)
|
||||
done < <(find src/Lean src/Std -name '*.lean' -print0)
|
||||
if [ -n "$failed_files" ]; then
|
||||
echo -e "The following files should use 'prelude':\n$failed_files"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
11
CODEOWNERS
11
CODEOWNERS
@@ -4,14 +4,14 @@
|
||||
# Listed persons will automatically be asked by GitHub to review a PR touching these paths.
|
||||
# If multiple names are listed, a review by any of them is considered sufficient by default.
|
||||
|
||||
/.github/ @Kha @semorrison
|
||||
/RELEASES.md @semorrison
|
||||
/.github/ @Kha @kim-em
|
||||
/RELEASES.md @kim-em
|
||||
/src/kernel/ @leodemoura
|
||||
/src/lake/ @tydeu
|
||||
/src/Lean/Compiler/ @leodemoura
|
||||
/src/Lean/Data/Lsp/ @mhuisi
|
||||
/src/Lean/Elab/Deriving/ @semorrison
|
||||
/src/Lean/Elab/Tactic/ @semorrison
|
||||
/src/Lean/Elab/Deriving/ @kim-em
|
||||
/src/Lean/Elab/Tactic/ @kim-em
|
||||
/src/Lean/Language/ @Kha
|
||||
/src/Lean/Meta/Tactic/ @leodemoura
|
||||
/src/Lean/Parser/ @Kha
|
||||
@@ -19,7 +19,7 @@
|
||||
/src/Lean/PrettyPrinter/Delaborator/ @kmill
|
||||
/src/Lean/Server/ @mhuisi
|
||||
/src/Lean/Widget/ @Vtec234
|
||||
/src/Init/Data/ @semorrison
|
||||
/src/Init/Data/ @kim-em
|
||||
/src/Init/Data/Array/Lemmas.lean @digama0
|
||||
/src/Init/Data/List/Lemmas.lean @digama0
|
||||
/src/Init/Data/List/BasicAux.lean @digama0
|
||||
@@ -45,3 +45,4 @@
|
||||
/src/Std/ @TwoFX
|
||||
/src/Std/Tactic/BVDecide/ @hargoniX
|
||||
/src/Lean/Elab/Tactic/BVDecide/ @hargoniX
|
||||
/src/Std/Sat/ @hargoniX
|
||||
|
||||
@@ -1937,15 +1937,6 @@ instance : Subsingleton (Squash α) where
|
||||
apply Quot.sound
|
||||
trivial
|
||||
|
||||
/-! # Relations -/
|
||||
|
||||
/--
|
||||
`Antisymm (·≤·)` says that `(·≤·)` is antisymmetric, that is, `a ≤ b → b ≤ a → a = b`.
|
||||
-/
|
||||
class Antisymm {α : Sort u} (r : α → α → Prop) : Prop where
|
||||
/-- An antisymmetric relation `(·≤·)` satisfies `a ≤ b → b ≤ a → a = b`. -/
|
||||
antisymm {a b : α} : r a b → r b a → a = b
|
||||
|
||||
namespace Lean
|
||||
/-! # Kernel reduction hints -/
|
||||
|
||||
@@ -2121,4 +2112,14 @@ instance : Commutative Or := ⟨fun _ _ => propext or_comm⟩
|
||||
instance : Commutative And := ⟨fun _ _ => propext and_comm⟩
|
||||
instance : Commutative Iff := ⟨fun _ _ => propext iff_comm⟩
|
||||
|
||||
/--
|
||||
`Antisymm (·≤·)` says that `(·≤·)` is antisymmetric, that is, `a ≤ b → b ≤ a → a = b`.
|
||||
-/
|
||||
class Antisymm (r : α → α → Prop) : Prop where
|
||||
/-- An antisymmetric relation `(·≤·)` satisfies `a ≤ b → b ≤ a → a = b`. -/
|
||||
antisymm {a b : α} : r a b → r b a → a = b
|
||||
|
||||
@[deprecated Antisymm (since := "2024-10-16"), inherit_doc Antisymm]
|
||||
abbrev _root_.Antisymm (r : α → α → Prop) : Prop := Std.Antisymm r
|
||||
|
||||
end Std
|
||||
|
||||
@@ -16,3 +16,4 @@ import Init.Data.Array.Lemmas
|
||||
import Init.Data.Array.TakeDrop
|
||||
import Init.Data.Array.Bootstrap
|
||||
import Init.Data.Array.GetLit
|
||||
import Init.Data.Array.MapIdx
|
||||
|
||||
@@ -25,6 +25,8 @@ variable {α : Type u}
|
||||
|
||||
namespace Array
|
||||
|
||||
@[deprecated size (since := "2024-10-13")] abbrev data := @toList
|
||||
|
||||
/-! ### Preliminary theorems -/
|
||||
|
||||
@[simp] theorem size_set (a : Array α) (i : Fin a.size) (v : α) : (set a i v).size = a.size :=
|
||||
@@ -817,9 +819,15 @@ def split (as : Array α) (p : α → Bool) : Array α × Array α :=
|
||||
|
||||
/-! ## Auxiliary functions used in metaprogramming.
|
||||
|
||||
We do not intend to provide verification theorems for these functions.
|
||||
We do not currently intend to provide verification theorems for these functions.
|
||||
-/
|
||||
|
||||
/- ### reduceOption -/
|
||||
|
||||
/-- Drop `none`s from a Array, and replace each remaining `some a` with `a`. -/
|
||||
@[inline] def reduceOption (as : Array (Option α)) : Array α :=
|
||||
as.filterMap id
|
||||
|
||||
/-! ### eraseReps -/
|
||||
|
||||
/--
|
||||
|
||||
@@ -8,13 +8,12 @@ import Init.Data.Nat.Lemmas
|
||||
import Init.Data.List.Impl
|
||||
import Init.Data.List.Monadic
|
||||
import Init.Data.List.Range
|
||||
import Init.Data.List.Nat.TakeDrop
|
||||
import Init.Data.Array.Mem
|
||||
import Init.TacticsExtra
|
||||
|
||||
/-!
|
||||
## Bootstrapping theorems about arrays
|
||||
|
||||
This file contains some theorems about `Array` and `List` needed for `Init.Data.List.Impl`.
|
||||
## Theorems about `Array`.
|
||||
-/
|
||||
|
||||
namespace Array
|
||||
@@ -45,21 +44,32 @@ theorem getElem?_eq_getElem?_toList (a : Array α) (i : Nat) : a[i]? = a.toList[
|
||||
rw [getElem?_eq]
|
||||
split <;> simp_all
|
||||
|
||||
theorem get_push_lt (a : Array α) (x : α) (i : Nat) (h : i < a.size) :
|
||||
theorem getElem_push_lt (a : Array α) (x : α) (i : Nat) (h : i < a.size) :
|
||||
have : i < (a.push x).size := by simp [*, Nat.lt_succ_of_le, Nat.le_of_lt]
|
||||
(a.push x)[i] = a[i] := by
|
||||
simp only [push, getElem_eq_getElem_toList, List.concat_eq_append, List.getElem_append_left, h]
|
||||
|
||||
@[simp] theorem get_push_eq (a : Array α) (x : α) : (a.push x)[a.size] = x := by
|
||||
@[simp] theorem getElem_push_eq (a : Array α) (x : α) : (a.push x)[a.size] = x := by
|
||||
simp only [push, getElem_eq_getElem_toList, List.concat_eq_append]
|
||||
rw [List.getElem_append_right] <;> simp [getElem_eq_getElem_toList, Nat.zero_lt_one]
|
||||
|
||||
theorem get_push (a : Array α) (x : α) (i : Nat) (h : i < (a.push x).size) :
|
||||
theorem getElem_push (a : Array α) (x : α) (i : Nat) (h : i < (a.push x).size) :
|
||||
(a.push x)[i] = if h : i < a.size then a[i] else x := by
|
||||
by_cases h' : i < a.size
|
||||
· simp [get_push_lt, h']
|
||||
· simp [getElem_push_lt, h']
|
||||
· simp at h
|
||||
simp [get_push_lt, Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.ge_of_not_lt h')]
|
||||
simp [getElem_push_lt, Nat.le_antisymm (Nat.le_of_lt_succ h) (Nat.ge_of_not_lt h')]
|
||||
|
||||
@[deprecated getElem_push (since := "2024-10-21")] abbrev get_push := @getElem_push
|
||||
@[deprecated getElem_push_lt (since := "2024-10-21")] abbrev get_push_lt := @getElem_push_lt
|
||||
@[deprecated getElem_push_eq (since := "2024-10-21")] abbrev get_push_eq := @getElem_push_eq
|
||||
|
||||
@[simp] theorem get!_eq_getElem! [Inhabited α] (a : Array α) (i : Nat) : a.get! i = a[i]! := by
|
||||
simp [getElem!_def, get!, getD]
|
||||
split <;> rename_i h
|
||||
· simp [getElem?_eq_getElem h]
|
||||
rfl
|
||||
· simp [getElem?_eq_none_iff.2 (by simpa using h)]
|
||||
|
||||
end Array
|
||||
|
||||
@@ -83,6 +93,9 @@ We prefer to pull `List.toArray` outwards.
|
||||
|
||||
@[simp] theorem getElem?_toArray {a : List α} {i : Nat} : a.toArray[i]? = a[i]? := rfl
|
||||
|
||||
@[simp] theorem getElem!_toArray [Inhabited α] {a : List α} {i : Nat} :
|
||||
a.toArray[i]! = a[i]! := rfl
|
||||
|
||||
@[simp] theorem push_toArray (l : List α) (a : α) : l.toArray.push a = (l ++ [a]).toArray := by
|
||||
apply ext'
|
||||
simp
|
||||
@@ -92,6 +105,14 @@ We prefer to pull `List.toArray` outwards.
|
||||
funext a
|
||||
simp
|
||||
|
||||
@[simp] theorem isEmpty_toArray (l : List α) : l.toArray.isEmpty = l.isEmpty := by
|
||||
cases l <;> simp
|
||||
|
||||
@[simp] theorem toArray_singleton (a : α) : (List.singleton a).toArray = singleton a := rfl
|
||||
|
||||
@[simp] theorem back_toArray [Inhabited α] (l : List α) : l.toArray.back = l.getLast! := by
|
||||
simp only [back, size_toArray, Array.get!_eq_getElem!, getElem!_toArray, getLast!_eq_getElem!]
|
||||
|
||||
theorem foldrM_toArray [Monad m] (f : α → β → m β) (init : β) (l : List α) :
|
||||
l.toArray.foldrM f init = l.foldrM f init := by
|
||||
rw [foldrM_eq_reverse_foldlM_toList]
|
||||
@@ -250,7 +271,7 @@ theorem size_uset (a : Array α) (v i h) : (uset a i v h).size = a.size := by si
|
||||
@[simp] theorem get_eq_getElem (a : Array α) (i : Fin _) : a.get i = a[i.1] := rfl
|
||||
|
||||
theorem getElem?_lt
|
||||
(a : Array α) {i : Nat} (h : i < a.size) : a[i]? = some (a[i]) := dif_pos h
|
||||
(a : Array α) {i : Nat} (h : i < a.size) : a[i]? = some a[i] := dif_pos h
|
||||
|
||||
theorem getElem?_ge
|
||||
(a : Array α) {i : Nat} (h : i ≥ a.size) : a[i]? = none := dif_neg (Nat.not_lt_of_le h)
|
||||
@@ -273,8 +294,10 @@ theorem getD_get? (a : Array α) (i : Nat) (d : α) :
|
||||
|
||||
theorem get!_eq_getD [Inhabited α] (a : Array α) : a.get! n = a.getD n default := rfl
|
||||
|
||||
@[simp] theorem get!_eq_getElem? [Inhabited α] (a : Array α) (i : Nat) : a.get! i = (a.get? i).getD default := by
|
||||
by_cases p : i < a.size <;> simp [getD_get?, get!_eq_getD, p]
|
||||
@[simp] theorem get!_eq_getElem? [Inhabited α] (a : Array α) (i : Nat) :
|
||||
a.get! i = (a.get? i).getD default := by
|
||||
by_cases p : i < a.size <;>
|
||||
simp only [get!_eq_getD, getD_eq_get?, getD_get?, p, get?_eq_getElem?]
|
||||
|
||||
/-! # set -/
|
||||
|
||||
@@ -354,8 +377,8 @@ theorem getElem_ofFn_go (f : Fin n → α) (i) {acc k}
|
||||
simp only [dif_pos hin]
|
||||
rw [getElem_ofFn_go f (i+1) _ hin (by simp [*]) (fun j hj => ?hacc)]
|
||||
cases (Nat.lt_or_eq_of_le <| Nat.le_of_lt_succ (by simpa using hj)) with
|
||||
| inl hj => simp [get_push, hj, hacc j hj]
|
||||
| inr hj => simp [get_push, *]
|
||||
| inl hj => simp [getElem_push, hj, hacc j hj]
|
||||
| inr hj => simp [getElem_push, *]
|
||||
else
|
||||
simp [hin, hacc k (Nat.lt_of_lt_of_le hki (Nat.le_of_not_lt (hi ▸ hin)))]
|
||||
termination_by n - i
|
||||
@@ -423,7 +446,7 @@ theorem lt_of_getElem {x : α} {a : Array α} {idx : Nat} {hidx : idx < a.size}
|
||||
idx < a.size :=
|
||||
hidx
|
||||
|
||||
theorem getElem_mem {l : Array α} {i : Nat} (h : i < l.size) : l[i] ∈ l := by
|
||||
@[simp] theorem getElem_mem {l : Array α} {i : Nat} (h : i < l.size) : l[i] ∈ l := by
|
||||
erw [Array.mem_def, getElem_eq_getElem_toList]
|
||||
apply List.get_mem
|
||||
|
||||
@@ -432,9 +455,11 @@ theorem getElem_fin_eq_getElem_toList (a : Array α) (i : Fin a.size) : a[i] = a
|
||||
@[simp] theorem ugetElem_eq_getElem (a : Array α) {i : USize} (h : i.toNat < a.size) :
|
||||
a[i] = a[i.toNat] := rfl
|
||||
|
||||
theorem get?_len_le (a : Array α) (i : Nat) (h : a.size ≤ i) : a[i]? = none := by
|
||||
theorem getElem?_size_le (a : Array α) (i : Nat) (h : a.size ≤ i) : a[i]? = none := by
|
||||
simp [getElem?_neg, h]
|
||||
|
||||
@[deprecated getElem?_size_le (since := "2024-10-21")] abbrev get?_len_le := @getElem?_size_le
|
||||
|
||||
theorem getElem_mem_toList (a : Array α) (h : i < a.size) : a[i] ∈ a.toList := by
|
||||
simp only [getElem_eq_getElem_toList, List.getElem_mem]
|
||||
|
||||
@@ -442,35 +467,39 @@ theorem get?_eq_get?_toList (a : Array α) (i : Nat) : a.get? i = a.toList.get?
|
||||
simp [getElem?_eq_getElem?_toList]
|
||||
|
||||
theorem get!_eq_get? [Inhabited α] (a : Array α) : a.get! n = (a.get? n).getD default := by
|
||||
simp [get!_eq_getD]
|
||||
simp only [get!_eq_getElem?, get?_eq_getElem?]
|
||||
|
||||
theorem getElem?_eq_some_iff {as : Array α} : as[n]? = some a ↔ ∃ h : n < as.size, as[n] = a := by
|
||||
cases as
|
||||
simp [List.getElem?_eq_some_iff]
|
||||
|
||||
@[simp] theorem back_eq_back? [Inhabited α] (a : Array α) : a.back = a.back?.getD default := by
|
||||
simp [back, back?]
|
||||
simp only [back, get!_eq_getElem?, get?_eq_getElem?, back?]
|
||||
|
||||
@[simp] theorem back?_push (a : Array α) : (a.push x).back? = some x := by
|
||||
simp [back?, getElem?_eq_getElem?_toList]
|
||||
|
||||
theorem back_push [Inhabited α] (a : Array α) : (a.push x).back = x := by simp
|
||||
|
||||
theorem get?_push_lt (a : Array α) (x : α) (i : Nat) (h : i < a.size) :
|
||||
theorem getElem?_push_lt (a : Array α) (x : α) (i : Nat) (h : i < a.size) :
|
||||
(a.push x)[i]? = some a[i] := by
|
||||
rw [getElem?_pos, get_push_lt]
|
||||
rw [getElem?_pos, getElem_push_lt]
|
||||
|
||||
theorem get?_push_eq (a : Array α) (x : α) : (a.push x)[a.size]? = some x := by
|
||||
rw [getElem?_pos, get_push_eq]
|
||||
@[deprecated getElem?_push_lt (since := "2024-10-21")] abbrev get?_push_lt := @getElem?_push_lt
|
||||
|
||||
theorem get?_push {a : Array α} : (a.push x)[i]? = if i = a.size then some x else a[i]? := by
|
||||
theorem getElem?_push_eq (a : Array α) (x : α) : (a.push x)[a.size]? = some x := by
|
||||
rw [getElem?_pos, getElem_push_eq]
|
||||
|
||||
@[deprecated getElem?_push_eq (since := "2024-10-21")] abbrev get?_push_eq := @getElem?_push_eq
|
||||
|
||||
theorem getElem?_push {a : Array α} : (a.push x)[i]? = if i = a.size then some x else a[i]? := by
|
||||
match Nat.lt_trichotomy i a.size with
|
||||
| Or.inl g =>
|
||||
have h1 : i < a.size + 1 := by omega
|
||||
have h2 : i ≠ a.size := by omega
|
||||
simp [getElem?_def, size_push, g, h1, h2, get_push_lt]
|
||||
simp [getElem?_def, size_push, g, h1, h2, getElem_push_lt]
|
||||
| Or.inr (Or.inl heq) =>
|
||||
simp [heq, getElem?_pos, get_push_eq]
|
||||
simp [heq, getElem?_pos, getElem_push_eq]
|
||||
| Or.inr (Or.inr g) =>
|
||||
simp only [getElem?_def, size_push]
|
||||
have h1 : ¬ (i < a.size) := by omega
|
||||
@@ -478,9 +507,13 @@ theorem get?_push {a : Array α} : (a.push x)[i]? = if i = a.size then some x el
|
||||
have h3 : i ≠ a.size := by omega
|
||||
simp [h1, h2, h3]
|
||||
|
||||
@[simp] theorem get?_size {a : Array α} : a[a.size]? = none := by
|
||||
@[deprecated getElem?_push (since := "2024-10-21")] abbrev get?_push := @getElem?_push
|
||||
|
||||
@[simp] theorem getElem?_size {a : Array α} : a[a.size]? = none := by
|
||||
simp only [getElem?_def, Nat.lt_irrefl, dite_false]
|
||||
|
||||
@[deprecated getElem?_size (since := "2024-10-21")] abbrev get?_size := @getElem?_size
|
||||
|
||||
@[simp] theorem toList_set (a : Array α) (i v) : (a.set i v).toList = a.toList.set i.1 v := rfl
|
||||
|
||||
theorem get_set_eq (a : Array α) (i : Fin a.size) (v : α) :
|
||||
@@ -530,6 +563,9 @@ theorem getElem?_swap (a : Array α) (i j : Fin a.size) (k : Nat) : (a.swap i j)
|
||||
@[simp] theorem swapAt_def (a : Array α) (i : Fin a.size) (v : α) :
|
||||
a.swapAt i v = (a[i.1], a.set i v) := rfl
|
||||
|
||||
@[simp] theorem size_swapAt (a : Array α) (i : Fin a.size) (v : α) :
|
||||
(a.swapAt i v).2.size = a.size := by simp [swapAt_def]
|
||||
|
||||
@[simp]
|
||||
theorem swapAt!_def (a : Array α) (i : Nat) (v : α) (h : i < a.size) :
|
||||
a.swapAt! i v = (a[i], a.set ⟨i, h⟩ v) := by simp [swapAt!, h]
|
||||
@@ -562,11 +598,11 @@ theorem eq_push_pop_back_of_size_ne_zero [Inhabited α] {as : Array α} (h : as.
|
||||
· simp [Nat.sub_add_cancel (Nat.zero_lt_of_ne_zero h)]
|
||||
· intros i h h'
|
||||
if hlt : i < as.pop.size then
|
||||
rw [get_push_lt (h:=hlt), getElem_pop]
|
||||
rw [getElem_push_lt (h:=hlt), getElem_pop]
|
||||
else
|
||||
have heq : i = as.pop.size :=
|
||||
Nat.le_antisymm (size_pop .. ▸ Nat.le_pred_of_lt h) (Nat.le_of_not_gt hlt)
|
||||
cases heq; rw [get_push_eq, back, ←size_pop, get!_eq_getD, getD, dif_pos h]; rfl
|
||||
cases heq; rw [getElem_push_eq, back, ←size_pop, get!_eq_getD, getD, dif_pos h]; rfl
|
||||
|
||||
theorem eq_push_of_size_ne_zero {as : Array α} (h : as.size ≠ 0) :
|
||||
∃ (bs : Array α) (c : α), as = bs.push c :=
|
||||
@@ -775,9 +811,9 @@ theorem map_induction (as : Array α) (f : α → β) (motive : Nat → Prop) (h
|
||||
· intro j h
|
||||
simp at h ⊢
|
||||
by_cases h' : j < size b
|
||||
· rw [get_push]
|
||||
· rw [getElem_push]
|
||||
simp_all
|
||||
· rw [get_push, dif_neg h']
|
||||
· rw [getElem_push, dif_neg h']
|
||||
simp only [show j = i by omega]
|
||||
exact (hs _ m).1
|
||||
|
||||
@@ -802,7 +838,7 @@ theorem map_spec (as : Array α) (f : α → β) (p : Fin as.size → β → Pro
|
||||
(as.push x).map f = (as.map f).push (f x) := by
|
||||
ext
|
||||
· simp
|
||||
· simp only [getElem_map, get_push, size_map]
|
||||
· simp only [getElem_map, getElem_push, size_map]
|
||||
split <;> rfl
|
||||
|
||||
@[simp] theorem map_pop {f : α → β} {as : Array α} :
|
||||
@@ -811,57 +847,6 @@ theorem map_spec (as : Array α) (f : α → β) (p : Fin as.size → β → Pro
|
||||
· simp
|
||||
· simp only [getElem_map, getElem_pop, size_map]
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
-- This could also be proved from `SatisfiesM_mapIdxM` in Batteries.
|
||||
theorem mapIdx_induction (as : Array α) (f : Fin as.size → α → β)
|
||||
(motive : Nat → Prop) (h0 : motive 0)
|
||||
(p : Fin as.size → β → Prop)
|
||||
(hs : ∀ i, motive i.1 → p i (f i as[i]) ∧ motive (i + 1)) :
|
||||
motive as.size ∧ ∃ eq : (Array.mapIdx as f).size = as.size,
|
||||
∀ i h, p ⟨i, h⟩ ((Array.mapIdx as f)[i]) := by
|
||||
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : ∀ i h h', p ⟨i, h⟩ bs[i]) (hm : motive j) :
|
||||
let arr : Array β := Array.mapIdxM.map (m := Id) as f i j h bs
|
||||
motive as.size ∧ ∃ eq : arr.size = as.size, ∀ i h, p ⟨i, h⟩ arr[i] := by
|
||||
induction i generalizing j bs with simp [mapIdxM.map]
|
||||
| zero =>
|
||||
have := (Nat.zero_add _).symm.trans h
|
||||
exact ⟨this ▸ hm, h₁ ▸ this, fun _ _ => h₂ ..⟩
|
||||
| succ i ih =>
|
||||
apply @ih (bs.push (f ⟨j, by omega⟩ as[j])) (j + 1) (by omega) (by simp; omega)
|
||||
· intro i i_lt h'
|
||||
rw [get_push]
|
||||
split
|
||||
· apply h₂
|
||||
· simp only [size_push] at h'
|
||||
obtain rfl : i = j := by omega
|
||||
apply (hs ⟨i, by omega⟩ hm).1
|
||||
· exact (hs ⟨j, by omega⟩ hm).2
|
||||
simp [mapIdx, mapIdxM]; exact go rfl nofun h0
|
||||
|
||||
theorem mapIdx_spec (as : Array α) (f : Fin as.size → α → β)
|
||||
(p : Fin as.size → β → Prop) (hs : ∀ i, p i (f i as[i])) :
|
||||
∃ eq : (Array.mapIdx as f).size = as.size,
|
||||
∀ i h, p ⟨i, h⟩ ((Array.mapIdx as f)[i]) :=
|
||||
(mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ => ⟨hs .., trivial⟩).2
|
||||
|
||||
@[simp] theorem size_mapIdx (a : Array α) (f : Fin a.size → α → β) : (a.mapIdx f).size = a.size :=
|
||||
(mapIdx_spec (p := fun _ _ => True) (hs := fun _ => trivial)).1
|
||||
|
||||
@[simp] theorem size_zipWithIndex (as : Array α) : as.zipWithIndex.size = as.size :=
|
||||
Array.size_mapIdx _ _
|
||||
|
||||
@[simp] theorem getElem_mapIdx (a : Array α) (f : Fin a.size → α → β) (i : Nat)
|
||||
(h : i < (mapIdx a f).size) :
|
||||
(a.mapIdx f)[i] = f ⟨i, by simp_all⟩ (a[i]'(by simp_all)) :=
|
||||
(mapIdx_spec _ _ (fun i b => b = f i a[i]) fun _ => rfl).2 i _
|
||||
|
||||
@[simp] theorem getElem?_mapIdx (a : Array α) (f : Fin a.size → α → β) (i : Nat) :
|
||||
(a.mapIdx f)[i]? =
|
||||
a[i]?.pbind fun b h => f ⟨i, (getElem?_eq_some_iff.1 h).1⟩ b := by
|
||||
simp only [getElem?_def, size_mapIdx, getElem_mapIdx]
|
||||
split <;> simp_all
|
||||
|
||||
/-! ### modify -/
|
||||
|
||||
@[simp] theorem size_modify (a : Array α) (i : Nat) (f : α → α) : (a.modify i f).size = a.size := by
|
||||
@@ -884,6 +869,11 @@ theorem getElem_modify_of_ne {as : Array α} {i : Nat} (h : i ≠ j)
|
||||
(as.modify i f)[j] = as[j]'(by simpa using hj) := by
|
||||
simp [getElem_modify hj, h]
|
||||
|
||||
theorem getElem?_modify {as : Array α} {i : Nat} {f : α → α} {j : Nat} :
|
||||
(as.modify i f)[j]? = if i = j then as[j]?.map f else as[j]? := by
|
||||
simp only [getElem?_def, size_modify, getElem_modify, Option.map_dif]
|
||||
split <;> split <;> rfl
|
||||
|
||||
/-! ### filter -/
|
||||
|
||||
@[simp] theorem toList_filter (p : α → Bool) (l : Array α) :
|
||||
@@ -945,7 +935,7 @@ theorem filterMap_congr {as bs : Array α} (h : as = bs)
|
||||
|
||||
theorem size_empty : (#[] : Array α).size = 0 := rfl
|
||||
|
||||
theorem toList_empty : (#[] : Array α).toList = [] := rfl
|
||||
@[simp] theorem toList_empty : (#[] : Array α).toList = [] := rfl
|
||||
|
||||
/-! ### append -/
|
||||
|
||||
@@ -1103,7 +1093,7 @@ theorem getElem_extract_loop_ge (as bs : Array α) (size start : Nat) (hge : i
|
||||
have h₂ : bs.size < (extract.loop as size (start+1) (bs.push as[start])).size := by
|
||||
rw [size_extract_loop]; apply Nat.lt_of_lt_of_le h₁; exact Nat.le_add_right ..
|
||||
have h : (extract.loop as size (start + 1) (push bs as[start]))[bs.size] = as[start] := by
|
||||
rw [getElem_extract_loop_lt as (bs.push as[start]) size (start+1) h₁ h₂, get_push_eq]
|
||||
rw [getElem_extract_loop_lt as (bs.push as[start]) size (start+1) h₁ h₂, getElem_push_eq]
|
||||
rw [h]; congr; rw [Nat.add_sub_cancel]
|
||||
else
|
||||
have hge : bs.size + 1 ≤ i := Nat.lt_of_le_of_ne hge hi
|
||||
@@ -1130,6 +1120,14 @@ theorem getElem?_extract {as : Array α} {start stop : Nat} :
|
||||
· omega
|
||||
· rfl
|
||||
|
||||
@[simp] theorem toList_extract (as : Array α) (start stop : Nat) :
|
||||
(as.extract start stop).toList = (as.toList.drop start).take (stop - start) := by
|
||||
apply List.ext_getElem
|
||||
· simp only [length_toList, size_extract, List.length_take, List.length_drop]
|
||||
omega
|
||||
· intros n h₁ h₂
|
||||
simp
|
||||
|
||||
@[simp] theorem extract_all (as : Array α) : as.extract 0 as.size = as := by
|
||||
apply ext
|
||||
· rw [size_extract, Nat.min_self, Nat.sub_zero]
|
||||
@@ -1299,7 +1297,7 @@ open Fin
|
||||
· assumption
|
||||
|
||||
theorem getElem_swap' (a : Array α) (i j : Fin a.size) (k : Nat) (hk : k < a.size) :
|
||||
(a.swap i j)[k]'(by simp_all) = if k = i then a[j] else if k = j then a[i] else a[k] := by
|
||||
(a.swap i j)[k]'(by simp_all) = if k = i then a[j] else if k = j then a[i] else a[k] := by
|
||||
split
|
||||
· simp_all only [getElem_swap_left]
|
||||
· split <;> simp_all
|
||||
@@ -1309,7 +1307,7 @@ theorem getElem_swap (a : Array α) (i j : Fin a.size) (k : Nat) (hk : k < (a.sw
|
||||
apply getElem_swap'
|
||||
|
||||
@[simp] theorem swap_swap (a : Array α) {i j : Fin a.size} :
|
||||
(a.swap i j).swap ⟨i.1, (a.size_swap ..).symm ▸i.2⟩ ⟨j.1, (a.size_swap ..).symm ▸j.2⟩ = a := by
|
||||
(a.swap i j).swap ⟨i.1, (a.size_swap ..).symm ▸ i.2⟩ ⟨j.1, (a.size_swap ..).symm ▸ j.2⟩ = a := by
|
||||
apply ext
|
||||
· simp only [size_swap]
|
||||
· intros
|
||||
@@ -1472,6 +1470,11 @@ theorem filterMap_toArray (f : α → Option β) (l : List α) :
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
@[simp] theorem toArray_extract (l : List α) (start stop : Nat) :
|
||||
l.toArray.extract start stop = ((l.drop start).take (stop - start)).toArray := by
|
||||
apply ext'
|
||||
simp
|
||||
|
||||
end List
|
||||
|
||||
/-! ### Deprecations -/
|
||||
|
||||
64
src/Init/Data/Array/MapIdx.lean
Normal file
64
src/Init/Data/Array/MapIdx.lean
Normal file
@@ -0,0 +1,64 @@
|
||||
/-
|
||||
Copyright (c) 2022 Mario Carneiro. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mario Carneiro, Kim Morrison
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Array.Lemmas
|
||||
import Init.Data.List.MapIdx
|
||||
|
||||
namespace Array
|
||||
|
||||
|
||||
/-! ### mapIdx -/
|
||||
|
||||
-- This could also be proved from `SatisfiesM_mapIdxM` in Batteries.
|
||||
theorem mapIdx_induction (as : Array α) (f : Fin as.size → α → β)
|
||||
(motive : Nat → Prop) (h0 : motive 0)
|
||||
(p : Fin as.size → β → Prop)
|
||||
(hs : ∀ i, motive i.1 → p i (f i as[i]) ∧ motive (i + 1)) :
|
||||
motive as.size ∧ ∃ eq : (Array.mapIdx as f).size = as.size,
|
||||
∀ i h, p ⟨i, h⟩ ((Array.mapIdx as f)[i]) := by
|
||||
let rec go {bs i j h} (h₁ : j = bs.size) (h₂ : ∀ i h h', p ⟨i, h⟩ bs[i]) (hm : motive j) :
|
||||
let arr : Array β := Array.mapIdxM.map (m := Id) as f i j h bs
|
||||
motive as.size ∧ ∃ eq : arr.size = as.size, ∀ i h, p ⟨i, h⟩ arr[i] := by
|
||||
induction i generalizing j bs with simp [mapIdxM.map]
|
||||
| zero =>
|
||||
have := (Nat.zero_add _).symm.trans h
|
||||
exact ⟨this ▸ hm, h₁ ▸ this, fun _ _ => h₂ ..⟩
|
||||
| succ i ih =>
|
||||
apply @ih (bs.push (f ⟨j, by omega⟩ as[j])) (j + 1) (by omega) (by simp; omega)
|
||||
· intro i i_lt h'
|
||||
rw [getElem_push]
|
||||
split
|
||||
· apply h₂
|
||||
· simp only [size_push] at h'
|
||||
obtain rfl : i = j := by omega
|
||||
apply (hs ⟨i, by omega⟩ hm).1
|
||||
· exact (hs ⟨j, by omega⟩ hm).2
|
||||
simp [mapIdx, mapIdxM]; exact go rfl nofun h0
|
||||
|
||||
theorem mapIdx_spec (as : Array α) (f : Fin as.size → α → β)
|
||||
(p : Fin as.size → β → Prop) (hs : ∀ i, p i (f i as[i])) :
|
||||
∃ eq : (Array.mapIdx as f).size = as.size,
|
||||
∀ i h, p ⟨i, h⟩ ((Array.mapIdx as f)[i]) :=
|
||||
(mapIdx_induction _ _ (fun _ => True) trivial p fun _ _ => ⟨hs .., trivial⟩).2
|
||||
|
||||
@[simp] theorem size_mapIdx (a : Array α) (f : Fin a.size → α → β) : (a.mapIdx f).size = a.size :=
|
||||
(mapIdx_spec (p := fun _ _ => True) (hs := fun _ => trivial)).1
|
||||
|
||||
@[simp] theorem size_zipWithIndex (as : Array α) : as.zipWithIndex.size = as.size :=
|
||||
Array.size_mapIdx _ _
|
||||
|
||||
@[simp] theorem getElem_mapIdx (a : Array α) (f : Fin a.size → α → β) (i : Nat)
|
||||
(h : i < (mapIdx a f).size) :
|
||||
(a.mapIdx f)[i] = f ⟨i, by simp_all⟩ (a[i]'(by simp_all)) :=
|
||||
(mapIdx_spec _ _ (fun i b => b = f i a[i]) fun _ => rfl).2 i _
|
||||
|
||||
@[simp] theorem getElem?_mapIdx (a : Array α) (f : Fin a.size → α → β) (i : Nat) :
|
||||
(a.mapIdx f)[i]? =
|
||||
a[i]?.pbind fun b h => f ⟨i, (getElem?_eq_some_iff.1 h).1⟩ b := by
|
||||
simp only [getElem?_def, size_mapIdx, getElem_mapIdx]
|
||||
split <;> simp_all
|
||||
|
||||
end Array
|
||||
@@ -51,6 +51,9 @@ instance : Hashable USize where
|
||||
instance : Hashable (Fin n) where
|
||||
hash v := v.val.toUInt64
|
||||
|
||||
instance : Hashable Char where
|
||||
hash c := c.val.toUInt64
|
||||
|
||||
instance : Hashable Int where
|
||||
hash
|
||||
| Int.ofNat n => UInt64.ofNat (2 * n)
|
||||
|
||||
@@ -1418,11 +1418,15 @@ def sum {α} [Add α] [Zero α] : List α → α :=
|
||||
@[simp] theorem sum_cons [Add α] [Zero α] {a : α} {l : List α} : (a::l).sum = a + l.sum := rfl
|
||||
|
||||
/-- Sum of a list of natural numbers. -/
|
||||
-- We intend to subsequently deprecate this in favor of `List.sum`.
|
||||
@[deprecated List.sum (since := "2024-10-17")]
|
||||
protected def _root_.Nat.sum (l : List Nat) : Nat := l.foldr (·+·) 0
|
||||
|
||||
@[simp] theorem _root_.Nat.sum_nil : Nat.sum ([] : List Nat) = 0 := rfl
|
||||
@[simp] theorem _root_.Nat.sum_cons (a : Nat) (l : List Nat) :
|
||||
set_option linter.deprecated false in
|
||||
@[simp, deprecated sum_nil (since := "2024-10-17")]
|
||||
theorem _root_.Nat.sum_nil : Nat.sum ([] : List Nat) = 0 := rfl
|
||||
set_option linter.deprecated false in
|
||||
@[simp, deprecated sum_cons (since := "2024-10-17")]
|
||||
theorem _root_.Nat.sum_cons (a : Nat) (l : List Nat) :
|
||||
Nat.sum (a::l) = a + Nat.sum l := rfl
|
||||
|
||||
/-! ### range -/
|
||||
|
||||
@@ -232,7 +232,8 @@ theorem sizeOf_get [SizeOf α] (as : List α) (i : Fin as.length) : sizeOf (as.g
|
||||
apply Nat.lt_trans ih
|
||||
simp_arith
|
||||
|
||||
theorem le_antisymm [LT α] [s : Antisymm (¬ · < · : α → α → Prop)] {as bs : List α} (h₁ : as ≤ bs) (h₂ : bs ≤ as) : as = bs :=
|
||||
theorem le_antisymm [LT α] [s : Std.Antisymm (¬ · < · : α → α → Prop)]
|
||||
{as bs : List α} (h₁ : as ≤ bs) (h₂ : bs ≤ as) : as = bs :=
|
||||
match as, bs with
|
||||
| [], [] => rfl
|
||||
| [], _::_ => False.elim <| h₂ (List.lt.nil ..)
|
||||
@@ -248,7 +249,8 @@ theorem le_antisymm [LT α] [s : Antisymm (¬ · < · : α → α → Prop)] {as
|
||||
have : a = b := s.antisymm hab hba
|
||||
simp [this, ih]
|
||||
|
||||
instance [LT α] [Antisymm (¬ · < · : α → α → Prop)] : Antisymm (· ≤ · : List α → List α → Prop) where
|
||||
instance [LT α] [Std.Antisymm (¬ · < · : α → α → Prop)] :
|
||||
Std.Antisymm (· ≤ · : List α → List α → Prop) where
|
||||
antisymm h₁ h₂ := le_antisymm h₁ h₂
|
||||
|
||||
end List
|
||||
|
||||
@@ -1047,9 +1047,6 @@ theorem get_cons_length (x : α) (xs : List α) (n : Nat) (h : n = xs.length) :
|
||||
|
||||
@[simp] theorem getLast?_singleton (a : α) : getLast? [a] = a := rfl
|
||||
|
||||
theorem getLast!_of_getLast? [Inhabited α] : ∀ {l : List α}, getLast? l = some a → getLast! l = a
|
||||
| _ :: _, rfl => rfl
|
||||
|
||||
theorem getLast?_eq_getLast : ∀ l h, @getLast? α l = some (getLast l h)
|
||||
| [], h => nomatch h rfl
|
||||
| _ :: _, _ => rfl
|
||||
@@ -1083,6 +1080,21 @@ theorem getLast?_concat (l : List α) : getLast? (l ++ [a]) = some a := by
|
||||
theorem getLastD_concat (a b l) : @getLastD α (l ++ [b]) a = b := by
|
||||
rw [getLastD_eq_getLast?, getLast?_concat]; rfl
|
||||
|
||||
/-! ### getLast! -/
|
||||
|
||||
@[simp] theorem getLast!_nil [Inhabited α] : ([] : List α).getLast! = default := rfl
|
||||
|
||||
theorem getLast!_of_getLast? [Inhabited α] : ∀ {l : List α}, getLast? l = some a → getLast! l = a
|
||||
| _ :: _, rfl => rfl
|
||||
|
||||
theorem getLast!_eq_getElem! [Inhabited α] {l : List α} : l.getLast! = l[l.length - 1]! := by
|
||||
cases l with
|
||||
| nil => simp
|
||||
| cons _ _ =>
|
||||
apply getLast!_of_getLast?
|
||||
rw [getElem!_pos, getElem_cons_length (h := by simp)]
|
||||
rfl
|
||||
|
||||
/-! ## Head and tail -/
|
||||
|
||||
/-! ### head -/
|
||||
|
||||
@@ -75,7 +75,7 @@ theorem le_min?_iff [Min α] [LE α]
|
||||
|
||||
-- This could be refactored by designing appropriate typeclasses to replace `le_refl`, `min_eq_or`,
|
||||
-- and `le_min_iff`.
|
||||
theorem min?_eq_some_iff [Min α] [LE α] [anti : Antisymm ((· : α) ≤ ·)]
|
||||
theorem min?_eq_some_iff [Min α] [LE α] [anti : Std.Antisymm ((· : α) ≤ ·)]
|
||||
(le_refl : ∀ a : α, a ≤ a)
|
||||
(min_eq_or : ∀ a b : α, min a b = a ∨ min a b = b)
|
||||
(le_min_iff : ∀ a b c : α, a ≤ min b c ↔ a ≤ b ∧ a ≤ c) {xs : List α} :
|
||||
@@ -146,7 +146,7 @@ theorem max?_le_iff [Max α] [LE α]
|
||||
|
||||
-- This could be refactored by designing appropriate typeclasses to replace `le_refl`, `max_eq_or`,
|
||||
-- and `le_min_iff`.
|
||||
theorem max?_eq_some_iff [Max α] [LE α] [anti : Antisymm ((· : α) ≤ ·)]
|
||||
theorem max?_eq_some_iff [Max α] [LE α] [anti : Std.Antisymm ((· : α) ≤ ·)]
|
||||
(le_refl : ∀ a : α, a ≤ a)
|
||||
(max_eq_or : ∀ a b : α, max a b = a ∨ max a b = b)
|
||||
(max_le_iff : ∀ a b c : α, max b c ≤ a ↔ b ≤ a ∧ c ≤ a) {xs : List α} :
|
||||
|
||||
@@ -99,4 +99,14 @@ theorem allM_eq_not_anyM_not [Monad m] [LawfulMonad m] (p : α → m Bool) (as :
|
||||
funext b
|
||||
split <;> simp_all
|
||||
|
||||
/-! ### foldlM and foldrM -/
|
||||
|
||||
theorem foldlM_map [Monad m] (f : β₁ → β₂) (g : α → β₂ → m α) (l : List β₁) (init : α) :
|
||||
(l.map f).foldlM g init = l.foldlM (fun x y => g x (f y)) init := by
|
||||
induction l generalizing g init <;> simp [*]
|
||||
|
||||
theorem foldrM_map [Monad m] [LawfulMonad m] (f : β₁ → β₂) (g : β₂ → α → m α) (l : List β₁)
|
||||
(init : α) : (l.map f).foldrM g init = l.foldrM (fun x y => g (f x) y) init := by
|
||||
induction l generalizing g init <;> simp [*]
|
||||
|
||||
end List
|
||||
|
||||
@@ -490,10 +490,10 @@ protected theorem le_antisymm_iff {a b : Nat} : a = b ↔ a ≤ b ∧ b ≤ a :=
|
||||
(fun ⟨hle, hge⟩ => Nat.le_antisymm hle hge)
|
||||
protected theorem eq_iff_le_and_ge : ∀{a b : Nat}, a = b ↔ a ≤ b ∧ b ≤ a := @Nat.le_antisymm_iff
|
||||
|
||||
instance : Antisymm ( . ≤ . : Nat → Nat → Prop) where
|
||||
instance : Std.Antisymm ( . ≤ . : Nat → Nat → Prop) where
|
||||
antisymm h₁ h₂ := Nat.le_antisymm h₁ h₂
|
||||
|
||||
instance : Antisymm (¬ . < . : Nat → Nat → Prop) where
|
||||
instance : Std.Antisymm (¬ . < . : Nat → Nat → Prop) where
|
||||
antisymm h₁ h₂ := Nat.le_antisymm (Nat.ge_of_not_lt h₂) (Nat.ge_of_not_lt h₁)
|
||||
|
||||
protected theorem add_le_add_left {n m : Nat} (h : n ≤ m) (k : Nat) : k + n ≤ k + m :=
|
||||
|
||||
@@ -10,8 +10,10 @@ import Init.Data.Nat.Log2
|
||||
|
||||
/-- For decimal and scientific numbers (e.g., `1.23`, `3.12e10`).
|
||||
Examples:
|
||||
- `OfScientific.ofScientific 123 true 2` represents `1.23`
|
||||
- `OfScientific.ofScientific 121 false 100` represents `121e100`
|
||||
- `1.23` is syntax for `OfScientific.ofScientific (nat_lit 123) true (nat_lit 2)`
|
||||
- `121e100` is syntax for `OfScientific.ofScientific (nat_lit 121) false (nat_lit 100)`
|
||||
|
||||
Note the use of `nat_lit`; there is no wrapping `OfNat.ofNat` in the resulting term.
|
||||
-/
|
||||
class OfScientific (α : Type u) where
|
||||
ofScientific (mantissa : Nat) (exponentSign : Bool) (decimalExponent : Nat) : α
|
||||
|
||||
@@ -44,7 +44,7 @@ theorem attach_congr {o₁ o₂ : Option α} (h : o₁ = o₂) :
|
||||
simp
|
||||
|
||||
theorem attachWith_congr {o₁ o₂ : Option α} (w : o₁ = o₂) {P : α → Prop} {H : ∀ x ∈ o₁, P x} :
|
||||
o₁.attachWith P H = o₂.attachWith P fun x h => H _ (w ▸ h) := by
|
||||
o₁.attachWith P H = o₂.attachWith P fun _ h => H _ (w ▸ h) := by
|
||||
subst w
|
||||
simp
|
||||
|
||||
@@ -128,12 +128,12 @@ theorem attach_map {o : Option α} (f : α → β) :
|
||||
cases o <;> simp
|
||||
|
||||
theorem attachWith_map {o : Option α} (f : α → β) {P : β → Prop} {H : ∀ (b : β), b ∈ o.map f → P b} :
|
||||
(o.map f).attachWith P H = (o.attachWith (P ∘ f) (fun a h => H _ (mem_map_of_mem f h))).map
|
||||
(o.map f).attachWith P H = (o.attachWith (P ∘ f) (fun _ h => H _ (mem_map_of_mem f h))).map
|
||||
fun ⟨x, h⟩ => ⟨f x, h⟩ := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem map_attach {o : Option α} (f : { x // x ∈ o } → β) :
|
||||
o.attach.map f = o.pmap (fun a (h : a ∈ o) => f ⟨a, h⟩) (fun a h => h) := by
|
||||
o.attach.map f = o.pmap (fun a (h : a ∈ o) => f ⟨a, h⟩) (fun _ h => h) := by
|
||||
cases o <;> simp
|
||||
|
||||
theorem map_attachWith {o : Option α} {P : α → Prop} {H : ∀ (a : α), a ∈ o → P a}
|
||||
|
||||
@@ -1148,23 +1148,23 @@ namespace String
|
||||
/--
|
||||
If `pre` is a prefix of `s`, i.e. `s = pre ++ t`, returns the remainder `t`.
|
||||
-/
|
||||
def dropPrefix? (s : String) (pre : Substring) : Option Substring :=
|
||||
s.toSubstring.dropPrefix? pre
|
||||
def dropPrefix? (s : String) (pre : String) : Option Substring :=
|
||||
s.toSubstring.dropPrefix? pre.toSubstring
|
||||
|
||||
/--
|
||||
If `suff` is a suffix of `s`, i.e. `s = t ++ suff`, returns the remainder `t`.
|
||||
-/
|
||||
def dropSuffix? (s : String) (suff : Substring) : Option Substring :=
|
||||
s.toSubstring.dropSuffix? suff
|
||||
def dropSuffix? (s : String) (suff : String) : Option Substring :=
|
||||
s.toSubstring.dropSuffix? suff.toSubstring
|
||||
|
||||
/-- `s.stripPrefix pre` will remove `pre` from the beginning of `s` if it occurs there,
|
||||
or otherwise return `s`. -/
|
||||
def stripPrefix (s : String) (pre : Substring) : String :=
|
||||
def stripPrefix (s : String) (pre : String) : String :=
|
||||
s.dropPrefix? pre |>.map Substring.toString |>.getD s
|
||||
|
||||
/-- `s.stripSuffix suff` will remove `suff` from the end of `s` if it occurs there,
|
||||
or otherwise return `s`. -/
|
||||
def stripSuffix (s : String) (suff : Substring) : String :=
|
||||
def stripSuffix (s : String) (suff : String) : String :=
|
||||
s.dropSuffix? suff |>.map Substring.toString |>.getD s
|
||||
|
||||
end String
|
||||
|
||||
@@ -4,21 +4,5 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mario Carneiro, Yury G. Kudryashov
|
||||
-/
|
||||
prelude
|
||||
import Init.Core
|
||||
|
||||
namespace Sum
|
||||
|
||||
deriving instance DecidableEq for Sum
|
||||
deriving instance BEq for Sum
|
||||
|
||||
/-- Check if a sum is `inl` and if so, retrieve its contents. -/
|
||||
def getLeft? : α ⊕ β → Option α
|
||||
| inl a => some a
|
||||
| inr _ => none
|
||||
|
||||
/-- Check if a sum is `inr` and if so, retrieve its contents. -/
|
||||
def getRight? : α ⊕ β → Option β
|
||||
| inr b => some b
|
||||
| inl _ => none
|
||||
|
||||
end Sum
|
||||
import Init.Data.Sum.Basic
|
||||
import Init.Data.Sum.Lemmas
|
||||
|
||||
178
src/Init/Data/Sum/Basic.lean
Normal file
178
src/Init/Data/Sum/Basic.lean
Normal file
@@ -0,0 +1,178 @@
|
||||
/-
|
||||
Copyright (c) 2017 Mario Carneiro. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mario Carneiro, Yury G. Kudryashov
|
||||
-/
|
||||
prelude
|
||||
import Init.PropLemmas
|
||||
|
||||
/-!
|
||||
# Disjoint union of types
|
||||
|
||||
This file defines basic operations on the the sum type `α ⊕ β`.
|
||||
|
||||
`α ⊕ β` is the type made of a copy of `α` and a copy of `β`. It is also called *disjoint union*.
|
||||
|
||||
## Main declarations
|
||||
|
||||
* `Sum.isLeft`: Returns whether `x : α ⊕ β` comes from the left component or not.
|
||||
* `Sum.isRight`: Returns whether `x : α ⊕ β` comes from the right component or not.
|
||||
* `Sum.getLeft`: Retrieves the left content of a `x : α ⊕ β` that is known to come from the left.
|
||||
* `Sum.getRight`: Retrieves the right content of `x : α ⊕ β` that is known to come from the right.
|
||||
* `Sum.getLeft?`: Retrieves the left content of `x : α ⊕ β` as an option type or returns `none`
|
||||
if it's coming from the right.
|
||||
* `Sum.getRight?`: Retrieves the right content of `x : α ⊕ β` as an option type or returns `none`
|
||||
if it's coming from the left.
|
||||
* `Sum.map`: Maps `α ⊕ β` to `γ ⊕ δ` component-wise.
|
||||
* `Sum.elim`: Nondependent eliminator/induction principle for `α ⊕ β`.
|
||||
* `Sum.swap`: Maps `α ⊕ β` to `β ⊕ α` by swapping components.
|
||||
* `Sum.LiftRel`: The disjoint union of two relations.
|
||||
* `Sum.Lex`: Lexicographic order on `α ⊕ β` induced by a relation on `α` and a relation on `β`.
|
||||
|
||||
## Further material
|
||||
|
||||
See `Batteries.Data.Sum.Lemmas` for theorems about these definitions.
|
||||
|
||||
## Notes
|
||||
|
||||
The definition of `Sum` takes values in `Type _`. This effectively forbids `Prop`- valued sum types.
|
||||
To this effect, we have `PSum`, which takes value in `Sort _` and carries a more complicated
|
||||
universe signature in consequence. The `Prop` version is `Or`.
|
||||
-/
|
||||
|
||||
namespace Sum
|
||||
|
||||
deriving instance DecidableEq for Sum
|
||||
deriving instance BEq for Sum
|
||||
|
||||
section get
|
||||
|
||||
/-- Check if a sum is `inl`. -/
|
||||
def isLeft : α ⊕ β → Bool
|
||||
| inl _ => true
|
||||
| inr _ => false
|
||||
|
||||
/-- Check if a sum is `inr`. -/
|
||||
def isRight : α ⊕ β → Bool
|
||||
| inl _ => false
|
||||
| inr _ => true
|
||||
|
||||
/-- Retrieve the contents from a sum known to be `inl`.-/
|
||||
def getLeft : (ab : α ⊕ β) → ab.isLeft → α
|
||||
| inl a, _ => a
|
||||
|
||||
/-- Retrieve the contents from a sum known to be `inr`.-/
|
||||
def getRight : (ab : α ⊕ β) → ab.isRight → β
|
||||
| inr b, _ => b
|
||||
|
||||
/-- Check if a sum is `inl` and if so, retrieve its contents. -/
|
||||
def getLeft? : α ⊕ β → Option α
|
||||
| inl a => some a
|
||||
| inr _ => none
|
||||
|
||||
/-- Check if a sum is `inr` and if so, retrieve its contents. -/
|
||||
def getRight? : α ⊕ β → Option β
|
||||
| inr b => some b
|
||||
| inl _ => none
|
||||
|
||||
@[simp] theorem isLeft_inl : (inl x : α ⊕ β).isLeft = true := rfl
|
||||
@[simp] theorem isLeft_inr : (inr x : α ⊕ β).isLeft = false := rfl
|
||||
@[simp] theorem isRight_inl : (inl x : α ⊕ β).isRight = false := rfl
|
||||
@[simp] theorem isRight_inr : (inr x : α ⊕ β).isRight = true := rfl
|
||||
|
||||
@[simp] theorem getLeft_inl (h : (inl x : α ⊕ β).isLeft) : (inl x).getLeft h = x := rfl
|
||||
@[simp] theorem getRight_inr (h : (inr x : α ⊕ β).isRight) : (inr x).getRight h = x := rfl
|
||||
|
||||
@[simp] theorem getLeft?_inl : (inl x : α ⊕ β).getLeft? = some x := rfl
|
||||
@[simp] theorem getLeft?_inr : (inr x : α ⊕ β).getLeft? = none := rfl
|
||||
@[simp] theorem getRight?_inl : (inl x : α ⊕ β).getRight? = none := rfl
|
||||
@[simp] theorem getRight?_inr : (inr x : α ⊕ β).getRight? = some x := rfl
|
||||
|
||||
end get
|
||||
|
||||
/-- Define a function on `α ⊕ β` by giving separate definitions on `α` and `β`. -/
|
||||
protected def elim {α β γ} (f : α → γ) (g : β → γ) : α ⊕ β → γ :=
|
||||
fun x => Sum.casesOn x f g
|
||||
|
||||
@[simp] theorem elim_inl (f : α → γ) (g : β → γ) (x : α) :
|
||||
Sum.elim f g (inl x) = f x := rfl
|
||||
|
||||
@[simp] theorem elim_inr (f : α → γ) (g : β → γ) (x : β) :
|
||||
Sum.elim f g (inr x) = g x := rfl
|
||||
|
||||
/-- Map `α ⊕ β` to `α' ⊕ β'` sending `α` to `α'` and `β` to `β'`. -/
|
||||
protected def map (f : α → α') (g : β → β') : α ⊕ β → α' ⊕ β' :=
|
||||
Sum.elim (inl ∘ f) (inr ∘ g)
|
||||
|
||||
@[simp] theorem map_inl (f : α → α') (g : β → β') (x : α) : (inl x).map f g = inl (f x) := rfl
|
||||
|
||||
@[simp] theorem map_inr (f : α → α') (g : β → β') (x : β) : (inr x).map f g = inr (g x) := rfl
|
||||
|
||||
/-- Swap the factors of a sum type -/
|
||||
def swap : α ⊕ β → β ⊕ α := Sum.elim inr inl
|
||||
|
||||
@[simp] theorem swap_inl : swap (inl x : α ⊕ β) = inr x := rfl
|
||||
|
||||
@[simp] theorem swap_inr : swap (inr x : α ⊕ β) = inl x := rfl
|
||||
|
||||
section LiftRel
|
||||
|
||||
/-- Lifts pointwise two relations between `α` and `γ` and between `β` and `δ` to a relation between
|
||||
`α ⊕ β` and `γ ⊕ δ`. -/
|
||||
inductive LiftRel (r : α → γ → Prop) (s : β → δ → Prop) : α ⊕ β → γ ⊕ δ → Prop
|
||||
/-- `inl a` and `inl c` are related via `LiftRel r s` if `a` and `c` are related via `r`. -/
|
||||
| protected inl {a c} : r a c → LiftRel r s (inl a) (inl c)
|
||||
/-- `inr b` and `inr d` are related via `LiftRel r s` if `b` and `d` are related via `s`. -/
|
||||
| protected inr {b d} : s b d → LiftRel r s (inr b) (inr d)
|
||||
|
||||
@[simp] theorem liftRel_inl_inl : LiftRel r s (inl a) (inl c) ↔ r a c :=
|
||||
⟨fun h => by cases h; assumption, LiftRel.inl⟩
|
||||
|
||||
@[simp] theorem not_liftRel_inl_inr : ¬LiftRel r s (inl a) (inr d) := nofun
|
||||
|
||||
@[simp] theorem not_liftRel_inr_inl : ¬LiftRel r s (inr b) (inl c) := nofun
|
||||
|
||||
@[simp] theorem liftRel_inr_inr : LiftRel r s (inr b) (inr d) ↔ s b d :=
|
||||
⟨fun h => by cases h; assumption, LiftRel.inr⟩
|
||||
|
||||
instance {r : α → γ → Prop} {s : β → δ → Prop}
|
||||
[∀ a c, Decidable (r a c)] [∀ b d, Decidable (s b d)] :
|
||||
∀ (ab : α ⊕ β) (cd : γ ⊕ δ), Decidable (LiftRel r s ab cd)
|
||||
| inl _, inl _ => decidable_of_iff' _ liftRel_inl_inl
|
||||
| inl _, inr _ => Decidable.isFalse not_liftRel_inl_inr
|
||||
| inr _, inl _ => Decidable.isFalse not_liftRel_inr_inl
|
||||
| inr _, inr _ => decidable_of_iff' _ liftRel_inr_inr
|
||||
|
||||
end LiftRel
|
||||
|
||||
section Lex
|
||||
|
||||
/-- Lexicographic order for sum. Sort all the `inl a` before the `inr b`, otherwise use the
|
||||
respective order on `α` or `β`. -/
|
||||
inductive Lex (r : α → α → Prop) (s : β → β → Prop) : α ⊕ β → α ⊕ β → Prop
|
||||
/-- `inl a₁` and `inl a₂` are related via `Lex r s` if `a₁` and `a₂` are related via `r`. -/
|
||||
| protected inl {a₁ a₂} (h : r a₁ a₂) : Lex r s (inl a₁) (inl a₂)
|
||||
/-- `inr b₁` and `inr b₂` are related via `Lex r s` if `b₁` and `b₂` are related via `s`. -/
|
||||
| protected inr {b₁ b₂} (h : s b₁ b₂) : Lex r s (inr b₁) (inr b₂)
|
||||
/-- `inl a` and `inr b` are always related via `Lex r s`. -/
|
||||
| sep (a b) : Lex r s (inl a) (inr b)
|
||||
|
||||
attribute [simp] Lex.sep
|
||||
|
||||
@[simp] theorem lex_inl_inl : Lex r s (inl a₁) (inl a₂) ↔ r a₁ a₂ :=
|
||||
⟨fun h => by cases h; assumption, Lex.inl⟩
|
||||
|
||||
@[simp] theorem lex_inr_inr : Lex r s (inr b₁) (inr b₂) ↔ s b₁ b₂ :=
|
||||
⟨fun h => by cases h; assumption, Lex.inr⟩
|
||||
|
||||
@[simp] theorem lex_inr_inl : ¬Lex r s (inr b) (inl a) := nofun
|
||||
|
||||
instance instDecidableRelSumLex [DecidableRel r] [DecidableRel s] : DecidableRel (Lex r s)
|
||||
| inl _, inl _ => decidable_of_iff' _ lex_inl_inl
|
||||
| inl _, inr _ => Decidable.isTrue (Lex.sep _ _)
|
||||
| inr _, inl _ => Decidable.isFalse lex_inr_inl
|
||||
| inr _, inr _ => decidable_of_iff' _ lex_inr_inr
|
||||
|
||||
end Lex
|
||||
|
||||
end Sum
|
||||
251
src/Init/Data/Sum/Lemmas.lean
Normal file
251
src/Init/Data/Sum/Lemmas.lean
Normal file
@@ -0,0 +1,251 @@
|
||||
/-
|
||||
Copyright (c) 2017 Mario Carneiro. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mario Carneiro, Yury G. Kudryashov
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.Sum.Basic
|
||||
import Init.Ext
|
||||
|
||||
/-!
|
||||
# Disjoint union of types
|
||||
|
||||
Theorems about the definitions introduced in `Init.Data.Sum.Basic`.
|
||||
-/
|
||||
|
||||
open Function
|
||||
|
||||
namespace Sum
|
||||
|
||||
@[simp] protected theorem «forall» {p : α ⊕ β → Prop} :
|
||||
(∀ x, p x) ↔ (∀ a, p (inl a)) ∧ ∀ b, p (inr b) :=
|
||||
⟨fun h => ⟨fun _ => h _, fun _ => h _⟩, fun ⟨h₁, h₂⟩ => Sum.rec h₁ h₂⟩
|
||||
|
||||
@[simp] protected theorem «exists» {p : α ⊕ β → Prop} :
|
||||
(∃ x, p x) ↔ (∃ a, p (inl a)) ∨ ∃ b, p (inr b) :=
|
||||
⟨ fun
|
||||
| ⟨inl a, h⟩ => Or.inl ⟨a, h⟩
|
||||
| ⟨inr b, h⟩ => Or.inr ⟨b, h⟩,
|
||||
fun
|
||||
| Or.inl ⟨a, h⟩ => ⟨inl a, h⟩
|
||||
| Or.inr ⟨b, h⟩ => ⟨inr b, h⟩⟩
|
||||
|
||||
theorem forall_sum {γ : α ⊕ β → Sort _} (p : (∀ ab, γ ab) → Prop) :
|
||||
(∀ fab, p fab) ↔ (∀ fa fb, p (Sum.rec fa fb)) := by
|
||||
refine ⟨fun h fa fb => h _, fun h fab => ?_⟩
|
||||
have h1 : fab = Sum.rec (fun a => fab (Sum.inl a)) (fun b => fab (Sum.inr b)) := by
|
||||
apply funext
|
||||
rintro (_ | _) <;> rfl
|
||||
rw [h1]; exact h _ _
|
||||
|
||||
section get
|
||||
|
||||
@[simp] theorem inl_getLeft : ∀ (x : α ⊕ β) (h : x.isLeft), inl (x.getLeft h) = x
|
||||
| inl _, _ => rfl
|
||||
@[simp] theorem inr_getRight : ∀ (x : α ⊕ β) (h : x.isRight), inr (x.getRight h) = x
|
||||
| inr _, _ => rfl
|
||||
|
||||
@[simp] theorem getLeft?_eq_none_iff {x : α ⊕ β} : x.getLeft? = none ↔ x.isRight := by
|
||||
cases x <;> simp only [getLeft?, isRight, eq_self_iff_true, reduceCtorEq]
|
||||
|
||||
@[simp] theorem getRight?_eq_none_iff {x : α ⊕ β} : x.getRight? = none ↔ x.isLeft := by
|
||||
cases x <;> simp only [getRight?, isLeft, eq_self_iff_true, reduceCtorEq]
|
||||
|
||||
theorem eq_left_getLeft_of_isLeft : ∀ {x : α ⊕ β} (h : x.isLeft), x = inl (x.getLeft h)
|
||||
| inl _, _ => rfl
|
||||
|
||||
@[simp] theorem getLeft_eq_iff (h : x.isLeft) : x.getLeft h = a ↔ x = inl a := by
|
||||
cases x <;> simp at h ⊢
|
||||
|
||||
theorem eq_right_getRight_of_isRight : ∀ {x : α ⊕ β} (h : x.isRight), x = inr (x.getRight h)
|
||||
| inr _, _ => rfl
|
||||
|
||||
@[simp] theorem getRight_eq_iff (h : x.isRight) : x.getRight h = b ↔ x = inr b := by
|
||||
cases x <;> simp at h ⊢
|
||||
|
||||
@[simp] theorem getLeft?_eq_some_iff : x.getLeft? = some a ↔ x = inl a := by
|
||||
cases x <;> simp only [getLeft?, Option.some.injEq, inl.injEq, reduceCtorEq]
|
||||
|
||||
@[simp] theorem getRight?_eq_some_iff : x.getRight? = some b ↔ x = inr b := by
|
||||
cases x <;> simp only [getRight?, Option.some.injEq, inr.injEq, reduceCtorEq]
|
||||
|
||||
@[simp] theorem bnot_isLeft (x : α ⊕ β) : !x.isLeft = x.isRight := by cases x <;> rfl
|
||||
|
||||
@[simp] theorem isLeft_eq_false {x : α ⊕ β} : x.isLeft = false ↔ x.isRight := by cases x <;> simp
|
||||
|
||||
theorem not_isLeft {x : α ⊕ β} : ¬x.isLeft ↔ x.isRight := by simp
|
||||
|
||||
@[simp] theorem bnot_isRight (x : α ⊕ β) : !x.isRight = x.isLeft := by cases x <;> rfl
|
||||
|
||||
@[simp] theorem isRight_eq_false {x : α ⊕ β} : x.isRight = false ↔ x.isLeft := by cases x <;> simp
|
||||
|
||||
theorem not_isRight {x : α ⊕ β} : ¬x.isRight ↔ x.isLeft := by simp
|
||||
|
||||
theorem isLeft_iff : x.isLeft ↔ ∃ y, x = Sum.inl y := by cases x <;> simp
|
||||
|
||||
theorem isRight_iff : x.isRight ↔ ∃ y, x = Sum.inr y := by cases x <;> simp
|
||||
|
||||
end get
|
||||
|
||||
theorem inl.inj_iff : (inl a : α ⊕ β) = inl b ↔ a = b := ⟨inl.inj, congrArg _⟩
|
||||
|
||||
theorem inr.inj_iff : (inr a : α ⊕ β) = inr b ↔ a = b := ⟨inr.inj, congrArg _⟩
|
||||
|
||||
theorem inl_ne_inr : inl a ≠ inr b := nofun
|
||||
|
||||
theorem inr_ne_inl : inr b ≠ inl a := nofun
|
||||
|
||||
/-! ### `Sum.elim` -/
|
||||
|
||||
@[simp] theorem elim_comp_inl (f : α → γ) (g : β → γ) : Sum.elim f g ∘ inl = f :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem elim_comp_inr (f : α → γ) (g : β → γ) : Sum.elim f g ∘ inr = g :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem elim_inl_inr : @Sum.elim α β _ inl inr = id :=
|
||||
funext fun x => Sum.casesOn x (fun _ => rfl) fun _ => rfl
|
||||
|
||||
theorem comp_elim (f : γ → δ) (g : α → γ) (h : β → γ) :
|
||||
f ∘ Sum.elim g h = Sum.elim (f ∘ g) (f ∘ h) :=
|
||||
funext fun x => Sum.casesOn x (fun _ => rfl) fun _ => rfl
|
||||
|
||||
@[simp] theorem elim_comp_inl_inr (f : α ⊕ β → γ) :
|
||||
Sum.elim (f ∘ inl) (f ∘ inr) = f :=
|
||||
funext fun x => Sum.casesOn x (fun _ => rfl) fun _ => rfl
|
||||
|
||||
theorem elim_eq_iff {u u' : α → γ} {v v' : β → γ} :
|
||||
Sum.elim u v = Sum.elim u' v' ↔ u = u' ∧ v = v' := by
|
||||
simp [funext_iff]
|
||||
|
||||
/-! ### `Sum.map` -/
|
||||
|
||||
@[simp] theorem map_map (f' : α' → α'') (g' : β' → β'') (f : α → α') (g : β → β') :
|
||||
∀ x : Sum α β, (x.map f g).map f' g' = x.map (f' ∘ f) (g' ∘ g)
|
||||
| inl _ => rfl
|
||||
| inr _ => rfl
|
||||
|
||||
@[simp] theorem map_comp_map (f' : α' → α'') (g' : β' → β'') (f : α → α') (g : β → β') :
|
||||
Sum.map f' g' ∘ Sum.map f g = Sum.map (f' ∘ f) (g' ∘ g) :=
|
||||
funext <| map_map f' g' f g
|
||||
|
||||
@[simp] theorem map_id_id : Sum.map (@id α) (@id β) = id :=
|
||||
funext fun x => Sum.recOn x (fun _ => rfl) fun _ => rfl
|
||||
|
||||
theorem elim_map {f₁ : α → β} {f₂ : β → ε} {g₁ : γ → δ} {g₂ : δ → ε} {x} :
|
||||
Sum.elim f₂ g₂ (Sum.map f₁ g₁ x) = Sum.elim (f₂ ∘ f₁) (g₂ ∘ g₁) x := by
|
||||
cases x <;> rfl
|
||||
|
||||
theorem elim_comp_map {f₁ : α → β} {f₂ : β → ε} {g₁ : γ → δ} {g₂ : δ → ε} :
|
||||
Sum.elim f₂ g₂ ∘ Sum.map f₁ g₁ = Sum.elim (f₂ ∘ f₁) (g₂ ∘ g₁) :=
|
||||
funext fun _ => elim_map
|
||||
|
||||
@[simp] theorem isLeft_map (f : α → β) (g : γ → δ) (x : α ⊕ γ) :
|
||||
isLeft (x.map f g) = isLeft x := by
|
||||
cases x <;> rfl
|
||||
|
||||
@[simp] theorem isRight_map (f : α → β) (g : γ → δ) (x : α ⊕ γ) :
|
||||
isRight (x.map f g) = isRight x := by
|
||||
cases x <;> rfl
|
||||
|
||||
@[simp] theorem getLeft?_map (f : α → β) (g : γ → δ) (x : α ⊕ γ) :
|
||||
(x.map f g).getLeft? = x.getLeft?.map f := by
|
||||
cases x <;> rfl
|
||||
|
||||
@[simp] theorem getRight?_map (f : α → β) (g : γ → δ) (x : α ⊕ γ) :
|
||||
(x.map f g).getRight? = x.getRight?.map g := by cases x <;> rfl
|
||||
|
||||
/-! ### `Sum.swap` -/
|
||||
|
||||
@[simp] theorem swap_swap (x : α ⊕ β) : swap (swap x) = x := by cases x <;> rfl
|
||||
|
||||
@[simp] theorem swap_swap_eq : swap ∘ swap = @id (α ⊕ β) := funext <| swap_swap
|
||||
|
||||
@[simp] theorem isLeft_swap (x : α ⊕ β) : x.swap.isLeft = x.isRight := by cases x <;> rfl
|
||||
|
||||
@[simp] theorem isRight_swap (x : α ⊕ β) : x.swap.isRight = x.isLeft := by cases x <;> rfl
|
||||
|
||||
@[simp] theorem getLeft?_swap (x : α ⊕ β) : x.swap.getLeft? = x.getRight? := by cases x <;> rfl
|
||||
|
||||
@[simp] theorem getRight?_swap (x : α ⊕ β) : x.swap.getRight? = x.getLeft? := by cases x <;> rfl
|
||||
|
||||
section LiftRel
|
||||
|
||||
theorem LiftRel.mono (hr : ∀ a b, r₁ a b → r₂ a b) (hs : ∀ a b, s₁ a b → s₂ a b)
|
||||
(h : LiftRel r₁ s₁ x y) : LiftRel r₂ s₂ x y := by
|
||||
cases h
|
||||
· exact LiftRel.inl (hr _ _ ‹_›)
|
||||
· exact LiftRel.inr (hs _ _ ‹_›)
|
||||
|
||||
theorem LiftRel.mono_left (hr : ∀ a b, r₁ a b → r₂ a b) (h : LiftRel r₁ s x y) :
|
||||
LiftRel r₂ s x y :=
|
||||
(h.mono hr) fun _ _ => id
|
||||
|
||||
theorem LiftRel.mono_right (hs : ∀ a b, s₁ a b → s₂ a b) (h : LiftRel r s₁ x y) :
|
||||
LiftRel r s₂ x y :=
|
||||
h.mono (fun _ _ => id) hs
|
||||
|
||||
protected theorem LiftRel.swap (h : LiftRel r s x y) : LiftRel s r x.swap y.swap := by
|
||||
cases h
|
||||
· exact LiftRel.inr ‹_›
|
||||
· exact LiftRel.inl ‹_›
|
||||
|
||||
@[simp] theorem liftRel_swap_iff : LiftRel s r x.swap y.swap ↔ LiftRel r s x y :=
|
||||
⟨fun h => by rw [← swap_swap x, ← swap_swap y]; exact h.swap, LiftRel.swap⟩
|
||||
|
||||
end LiftRel
|
||||
|
||||
section Lex
|
||||
|
||||
protected theorem LiftRel.lex {a b : α ⊕ β} (h : LiftRel r s a b) : Lex r s a b := by
|
||||
cases h
|
||||
· exact Lex.inl ‹_›
|
||||
· exact Lex.inr ‹_›
|
||||
|
||||
theorem liftRel_subrelation_lex : Subrelation (LiftRel r s) (Lex r s) := LiftRel.lex
|
||||
|
||||
theorem Lex.mono (hr : ∀ a b, r₁ a b → r₂ a b) (hs : ∀ a b, s₁ a b → s₂ a b) (h : Lex r₁ s₁ x y) :
|
||||
Lex r₂ s₂ x y := by
|
||||
cases h
|
||||
· exact Lex.inl (hr _ _ ‹_›)
|
||||
· exact Lex.inr (hs _ _ ‹_›)
|
||||
· exact Lex.sep _ _
|
||||
|
||||
theorem Lex.mono_left (hr : ∀ a b, r₁ a b → r₂ a b) (h : Lex r₁ s x y) : Lex r₂ s x y :=
|
||||
(h.mono hr) fun _ _ => id
|
||||
|
||||
theorem Lex.mono_right (hs : ∀ a b, s₁ a b → s₂ a b) (h : Lex r s₁ x y) : Lex r s₂ x y :=
|
||||
h.mono (fun _ _ => id) hs
|
||||
|
||||
theorem lex_acc_inl (aca : Acc r a) : Acc (Lex r s) (inl a) := by
|
||||
induction aca with
|
||||
| intro _ _ IH =>
|
||||
constructor
|
||||
intro y h
|
||||
cases h with
|
||||
| inl h' => exact IH _ h'
|
||||
|
||||
theorem lex_acc_inr (aca : ∀ a, Acc (Lex r s) (inl a)) {b} (acb : Acc s b) :
|
||||
Acc (Lex r s) (inr b) := by
|
||||
induction acb with
|
||||
| intro _ _ IH =>
|
||||
constructor
|
||||
intro y h
|
||||
cases h with
|
||||
| inr h' => exact IH _ h'
|
||||
| sep => exact aca _
|
||||
|
||||
theorem lex_wf (ha : WellFounded r) (hb : WellFounded s) : WellFounded (Lex r s) :=
|
||||
have aca : ∀ a, Acc (Lex r s) (inl a) := fun a => lex_acc_inl (ha.apply a)
|
||||
⟨fun x => Sum.recOn x aca fun b => lex_acc_inr aca (hb.apply b)⟩
|
||||
|
||||
end Lex
|
||||
|
||||
theorem elim_const_const (c : γ) :
|
||||
Sum.elim (const _ c : α → γ) (const _ c : β → γ) = const _ c := by
|
||||
apply funext
|
||||
rintro (_ | _) <;> rfl
|
||||
|
||||
@[simp] theorem elim_lam_const_lam_const (c : γ) :
|
||||
Sum.elim (fun _ : α => c) (fun _ : β => c) = fun _ => c :=
|
||||
Sum.elim_const_const c
|
||||
@@ -224,11 +224,7 @@ structure Config where
|
||||
-/
|
||||
index : Bool := true
|
||||
/--
|
||||
When `true` (default: `true`), `simp` will **not** create a proof for a rewriting rule associated
|
||||
with an `rfl`-theorem.
|
||||
Rewriting rules are provided by users by annotating theorems with the attribute `@[simp]`.
|
||||
If the proof of the theorem is just `rfl` (reflexivity), and `implicitDefEqProofs := true`, `simp`
|
||||
will **not** create a proof term which is an application of the annotated theorem.
|
||||
This option does not have any effect (yet).
|
||||
-/
|
||||
implicitDefEqProofs : Bool := true
|
||||
deriving Inhabited, BEq
|
||||
|
||||
@@ -168,9 +168,9 @@ end Lean
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander sorryAx] def unexpandSorryAx : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) _) => `(sorry)
|
||||
| `($(_) _ _) => `(sorry)
|
||||
| _ => throw ()
|
||||
| `($(_) $_) => `(sorry)
|
||||
| `($(_) $_ $_) => `(sorry)
|
||||
| _ => throw ()
|
||||
|
||||
@[app_unexpander Eq.ndrec] def unexpandEqNDRec : Lean.PrettyPrinter.Unexpander
|
||||
| `($(_) $m $h) => `($h ▸ $m)
|
||||
|
||||
@@ -135,6 +135,10 @@ Both reduce to `b = false ∧ c = false` via `not_or`.
|
||||
|
||||
theorem not_and_of_not_or_not (h : ¬a ∨ ¬b) : ¬(a ∧ b) := h.elim (mt (·.1)) (mt (·.2))
|
||||
|
||||
/-! ## not equal -/
|
||||
|
||||
theorem ne_of_apply_ne {α β : Sort _} (f : α → β) {x y : α} : f x ≠ f y → x ≠ y :=
|
||||
mt <| congrArg _
|
||||
|
||||
/-! ## Ite -/
|
||||
|
||||
@@ -384,6 +388,17 @@ theorem forall_prop_of_false {p : Prop} {q : p → Prop} (hn : ¬p) : (∀ h' :
|
||||
|
||||
end quantifiers
|
||||
|
||||
/-! ## membership -/
|
||||
|
||||
section Mem
|
||||
variable [Membership α β] {s t : β} {a b : α}
|
||||
|
||||
theorem ne_of_mem_of_not_mem (h : a ∈ s) : b ∉ s → a ≠ b := mt fun e => e ▸ h
|
||||
|
||||
theorem ne_of_mem_of_not_mem' (h : a ∈ s) : a ∉ t → s ≠ t := mt fun e => e ▸ h
|
||||
|
||||
end Mem
|
||||
|
||||
/-! ## Nonempty -/
|
||||
|
||||
@[simp] theorem nonempty_prop {p : Prop} : Nonempty p ↔ p :=
|
||||
|
||||
@@ -268,9 +268,9 @@ syntax (name := case') "case' " sepBy1(caseArg, " | ") " => " tacticSeq : tactic
|
||||
`next x₁ ... xₙ => tac` additionally renames the `n` most recent hypotheses with
|
||||
inaccessible names to the given names.
|
||||
-/
|
||||
macro "next " args:binderIdent* arrowTk:" => " tac:tacticSeq : tactic =>
|
||||
macro nextTk:"next " args:binderIdent* arrowTk:" => " tac:tacticSeq : tactic =>
|
||||
-- Limit ref variability for incrementality; see Note [Incremental Macros]
|
||||
withRef arrowTk `(tactic| case _ $args* =>%$arrowTk $tac)
|
||||
withRef arrowTk `(tactic| case%$nextTk _ $args* =>%$arrowTk $tac)
|
||||
|
||||
/-- `all_goals tac` runs `tac` on each goal, concatenating the resulting goals, if any. -/
|
||||
syntax (name := allGoals) "all_goals " tacticSeq : tactic
|
||||
|
||||
@@ -29,7 +29,6 @@ import Lean.Server
|
||||
import Lean.ScopedEnvExtension
|
||||
import Lean.DocString
|
||||
import Lean.DeclarationRange
|
||||
import Lean.LazyInitExtension
|
||||
import Lean.LoadDynlib
|
||||
import Lean.Widget
|
||||
import Lean.Log
|
||||
|
||||
@@ -12,16 +12,18 @@ import Lean.Elab.Eval
|
||||
import Lean.Elab.Command
|
||||
import Lean.Elab.Open
|
||||
import Lean.Elab.SetOption
|
||||
import Init.System.Platform
|
||||
|
||||
namespace Lean.Elab.Command
|
||||
|
||||
@[builtin_command_elab moduleDoc] def elabModuleDoc : CommandElab := fun stx => do
|
||||
match stx[1] with
|
||||
| Syntax.atom _ val =>
|
||||
let doc := val.extract 0 (val.endPos - ⟨2⟩)
|
||||
let range ← Elab.getDeclarationRange stx
|
||||
modifyEnv fun env => addMainModuleDoc env ⟨doc, range⟩
|
||||
| _ => throwErrorAt stx "unexpected module doc string{indentD stx[1]}"
|
||||
match stx[1] with
|
||||
| Syntax.atom _ val =>
|
||||
let doc := val.extract 0 (val.endPos - ⟨2⟩)
|
||||
let some range ← Elab.getDeclarationRange? stx
|
||||
| return -- must be from partial syntax, ignore
|
||||
modifyEnv fun env => addMainModuleDoc env ⟨doc, range⟩
|
||||
| _ => throwErrorAt stx "unexpected module doc string{indentD stx[1]}"
|
||||
|
||||
private def addScope (isNewNamespace : Bool) (isNoncomputable : Bool) (header : String) (newNamespace : Name) : CommandElabM Unit := do
|
||||
modify fun s => { s with
|
||||
@@ -403,6 +405,16 @@ def failIfSucceeds (x : CommandElabM Unit) : CommandElabM Unit := do
|
||||
includedVars := sc.includedVars.filter (!omittedVars.contains ·) }
|
||||
| _ => throwUnsupportedSyntax
|
||||
|
||||
@[builtin_command_elab version] def elabVersion : CommandElab := fun _ => do
|
||||
let mut target := System.Platform.target
|
||||
if target.isEmpty then target := "unknown"
|
||||
-- Only one should be set, but good to know if multiple are set in error.
|
||||
let platforms :=
|
||||
(if System.Platform.isWindows then [" Windows"] else [])
|
||||
++ (if System.Platform.isOSX then [" macOS"] else [])
|
||||
++ (if System.Platform.isEmscripten then [" Emscripten"] else [])
|
||||
logInfo m!"Lean {Lean.versionString}\nTarget: {target}{String.join platforms}"
|
||||
|
||||
@[builtin_command_elab Parser.Command.exit] def elabExit : CommandElab := fun _ =>
|
||||
logWarning "using 'exit' to interrupt Lean"
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ private def addAndCompileExprForEval (declName : Name) (value : Expr) (allowSorr
|
||||
-- An alternative design would be to make `elabTermForEval` into a term elaborator and elaborate the command all at once
|
||||
-- with `unsafe def _eval := term_for_eval% $t`, which we did try, but unwanted error messages
|
||||
-- such as "failed to infer definition type" can surface.
|
||||
let defView := mkDefViewOfDef { isUnsafe := true }
|
||||
let defView := mkDefViewOfDef { isUnsafe := true, stx := ⟨.missing⟩ }
|
||||
(← `(Parser.Command.definition|
|
||||
def $(mkIdent <| `_root_ ++ declName) := $(← Term.exprToSyntax value)))
|
||||
Term.elabMutualDef #[] { header := "" } #[defView]
|
||||
|
||||
@@ -135,13 +135,21 @@ open Meta
|
||||
| _ => Macro.throwUnsupported
|
||||
|
||||
@[builtin_macro Lean.Parser.Term.suffices] def expandSuffices : Macro
|
||||
| `(suffices%$tk $x:ident : $type from $val; $body) => `(have%$tk $x : $type := $body; $val)
|
||||
| `(suffices%$tk _%$x : $type from $val; $body) => `(have%$tk _%$x : $type := $body; $val)
|
||||
| `(suffices%$tk $hy:hygieneInfo $type from $val; $body) => `(have%$tk $hy:hygieneInfo : $type := $body; $val)
|
||||
| `(suffices%$tk $x:ident : $type by%$b $tac:tacticSeq; $body) => `(have%$tk $x : $type := $body; by%$b $tac)
|
||||
| `(suffices%$tk _%$x : $type by%$b $tac:tacticSeq; $body) => `(have%$tk _%$x : $type := $body; by%$b $tac)
|
||||
| `(suffices%$tk $hy:hygieneInfo $type by%$b $tac:tacticSeq; $body) => `(have%$tk $hy:hygieneInfo : $type := $body; by%$b $tac)
|
||||
| _ => Macro.throwUnsupported
|
||||
| `(suffices%$tk $x:ident : $type from $val; $body) => `(have%$tk $x : $type := $body; $val)
|
||||
| `(suffices%$tk _%$x : $type from $val; $body) => `(have%$tk _%$x : $type := $body; $val)
|
||||
| `(suffices%$tk $hy:hygieneInfo $type from $val; $body) => `(have%$tk $hy:hygieneInfo : $type := $body; $val)
|
||||
| `(suffices%$tk $x:ident : $type $b:byTactic'; $body) =>
|
||||
-- Pass on `SourceInfo` of `b` to `have`. This is necessary to display the goal state in the
|
||||
-- trailing whitespace of `by` and sound since `byTactic` and `byTactic'` are identical.
|
||||
let b := ⟨b.raw.setKind `Lean.Parser.Term.byTactic⟩
|
||||
`(have%$tk $x : $type := $body; $b:byTactic)
|
||||
| `(suffices%$tk _%$x : $type $b:byTactic'; $body) =>
|
||||
let b := ⟨b.raw.setKind `Lean.Parser.Term.byTactic⟩
|
||||
`(have%$tk _%$x : $type := $body; $b:byTactic)
|
||||
| `(suffices%$tk $hy:hygieneInfo $type $b:byTactic'; $body) =>
|
||||
let b := ⟨b.raw.setKind `Lean.Parser.Term.byTactic⟩
|
||||
`(have%$tk $hy:hygieneInfo : $type := $body; $b:byTactic)
|
||||
| _ => Macro.throwUnsupported
|
||||
|
||||
open Lean.Parser in
|
||||
private def elabParserMacroAux (prec e : Term) (withAnonymousAntiquot : Bool) : TermElabM Syntax := do
|
||||
|
||||
@@ -57,6 +57,7 @@ inductive RecKind where
|
||||
|
||||
/-- Flags and data added to declarations (eg docstrings, attributes, `private`, `unsafe`, `partial`, ...). -/
|
||||
structure Modifiers where
|
||||
stx : TSyntax ``Parser.Command.declModifiers
|
||||
docString? : Option String := none
|
||||
visibility : Visibility := Visibility.regular
|
||||
isNoncomputable : Bool := false
|
||||
@@ -121,16 +122,16 @@ section Methods
|
||||
variable [Monad m] [MonadEnv m] [MonadResolveName m] [MonadError m] [MonadMacroAdapter m] [MonadRecDepth m] [MonadTrace m] [MonadOptions m] [AddMessageContext m] [MonadLog m] [MonadInfoTree m] [MonadLiftT IO m]
|
||||
|
||||
/-- Elaborate declaration modifiers (i.e., attributes, `partial`, `private`, `protected`, `unsafe`, `noncomputable`, doc string)-/
|
||||
def elabModifiers (stx : Syntax) : m Modifiers := do
|
||||
let docCommentStx := stx[0]
|
||||
let attrsStx := stx[1]
|
||||
let visibilityStx := stx[2]
|
||||
let noncompStx := stx[3]
|
||||
let unsafeStx := stx[4]
|
||||
def elabModifiers (stx : TSyntax ``Parser.Command.declModifiers) : m Modifiers := do
|
||||
let docCommentStx := stx.raw[0]
|
||||
let attrsStx := stx.raw[1]
|
||||
let visibilityStx := stx.raw[2]
|
||||
let noncompStx := stx.raw[3]
|
||||
let unsafeStx := stx.raw[4]
|
||||
let recKind :=
|
||||
if stx[5].isNone then
|
||||
if stx.raw[5].isNone then
|
||||
RecKind.default
|
||||
else if stx[5][0].getKind == ``Parser.Command.partial then
|
||||
else if stx.raw[5][0].getKind == ``Parser.Command.partial then
|
||||
RecKind.partial
|
||||
else
|
||||
RecKind.nonrec
|
||||
@@ -148,7 +149,7 @@ def elabModifiers (stx : Syntax) : m Modifiers := do
|
||||
| none => pure #[]
|
||||
| some attrs => elabDeclAttrs attrs
|
||||
return {
|
||||
docString?, visibility, recKind, attrs,
|
||||
stx, docString?, visibility, recKind, attrs,
|
||||
isUnsafe := !unsafeStx.isNone
|
||||
isNoncomputable := !noncompStx.isNone
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ def elabAxiom (modifiers : Modifiers) (stx : Syntax) : CommandElabM Unit := do
|
||||
let (binders, typeStx) := expandDeclSig stx[2]
|
||||
let scopeLevelNames ← getLevelNames
|
||||
let ⟨_, declName, allUserLevelNames⟩ ← expandDeclId declId modifiers
|
||||
addDeclarationRanges declName stx
|
||||
addDeclarationRanges declName modifiers.stx stx
|
||||
runTermElabM fun vars =>
|
||||
Term.withDeclName declName <| Term.withLevelNames allUserLevelNames <| Term.elabBinders binders.getArgs fun xs => do
|
||||
Term.applyAttributesAt declName modifiers.attrs AttributeApplicationTime.beforeElaboration
|
||||
@@ -144,10 +144,10 @@ private def inductiveSyntaxToView (modifiers : Modifiers) (decl : Syntax) : Comm
|
||||
let (binders, type?) := expandOptDeclSig decl[2]
|
||||
let declId := decl[1]
|
||||
let ⟨name, declName, levelNames⟩ ← expandDeclId declId modifiers
|
||||
addDeclarationRanges declName decl
|
||||
addDeclarationRanges declName modifiers.stx decl
|
||||
let ctors ← decl[4].getArgs.mapM fun ctor => withRef ctor do
|
||||
-- def ctor := leading_parser optional docComment >> "\n| " >> declModifiers >> rawIdent >> optDeclSig
|
||||
let mut ctorModifiers ← elabModifiers ctor[2]
|
||||
let mut ctorModifiers ← elabModifiers ⟨ctor[2]⟩
|
||||
if let some leadingDocComment := ctor[0].getOptional? then
|
||||
if ctorModifiers.docString?.isSome then
|
||||
logErrorAt leadingDocComment "duplicate doc string"
|
||||
@@ -214,17 +214,18 @@ def elabDeclaration : CommandElab := fun stx => do
|
||||
-- only case implementing incrementality currently
|
||||
elabMutualDef #[stx]
|
||||
else withoutCommandIncrementality true do
|
||||
let modifiers : TSyntax ``Parser.Command.declModifiers := ⟨stx[0]⟩
|
||||
if declKind == ``Lean.Parser.Command.«axiom» then
|
||||
let modifiers ← elabModifiers stx[0]
|
||||
let modifiers ← elabModifiers modifiers
|
||||
elabAxiom modifiers decl
|
||||
else if declKind == ``Lean.Parser.Command.«inductive» then
|
||||
let modifiers ← elabModifiers stx[0]
|
||||
let modifiers ← elabModifiers modifiers
|
||||
elabInductive modifiers decl
|
||||
else if declKind == ``Lean.Parser.Command.classInductive then
|
||||
let modifiers ← elabModifiers stx[0]
|
||||
let modifiers ← elabModifiers modifiers
|
||||
elabClassInductive modifiers decl
|
||||
else if declKind == ``Lean.Parser.Command.«structure» then
|
||||
let modifiers ← elabModifiers stx[0]
|
||||
let modifiers ← elabModifiers modifiers
|
||||
elabStructure modifiers decl
|
||||
else
|
||||
throwError "unexpected declaration"
|
||||
@@ -238,7 +239,7 @@ private def isMutualInductive (stx : Syntax) : Bool :=
|
||||
|
||||
private def elabMutualInductive (elems : Array Syntax) : CommandElabM Unit := do
|
||||
let views ← elems.mapM fun stx => do
|
||||
let modifiers ← elabModifiers stx[0]
|
||||
let modifiers ← elabModifiers ⟨stx[0]⟩
|
||||
inductiveSyntaxToView modifiers stx[1]
|
||||
elabInductiveViews views
|
||||
|
||||
@@ -399,7 +400,7 @@ def elabMutual : CommandElab := fun stx => do
|
||||
-- We need to add `id`'s ranges *before* elaborating `initFn` (and then `id` itself) as
|
||||
-- otherwise the info context created by `with_decl_name` will be incomplete and break the
|
||||
-- call hierarchy
|
||||
addDeclarationRanges fullId defStx
|
||||
addDeclarationRanges fullId ⟨defStx.raw[0]⟩ defStx.raw[1]
|
||||
elabCommand (← `(
|
||||
$[unsafe%$unsafe?]? def initFn : IO $type := with_decl_name% $(mkIdent fullId) do $doSeq
|
||||
$defStx:command))
|
||||
|
||||
@@ -11,12 +11,14 @@ import Lean.Data.Lsp.Utf16
|
||||
|
||||
namespace Lean.Elab
|
||||
|
||||
def getDeclarationRange [Monad m] [MonadFileMap m] (stx : Syntax) : m DeclarationRange := do
|
||||
def getDeclarationRange? [Monad m] [MonadFileMap m] (stx : Syntax) : m (Option DeclarationRange) := do
|
||||
let some range := stx.getRange?
|
||||
| return none
|
||||
let fileMap ← getFileMap
|
||||
let pos := stx.getPos?.getD 0
|
||||
let endPos := stx.getTailPos?.getD pos |> fileMap.toPosition
|
||||
let pos := pos |> fileMap.toPosition
|
||||
return {
|
||||
--let range := fileMap.utf8RangeToLspRange
|
||||
let pos := fileMap.toPosition range.start
|
||||
let endPos := fileMap.toPosition range.stop
|
||||
return some {
|
||||
pos := pos
|
||||
charUtf16 := fileMap.leanPosToLspPos pos |>.character
|
||||
endPos := endPos
|
||||
@@ -49,23 +51,27 @@ def getDeclarationSelectionRef (stx : Syntax) : Syntax :=
|
||||
|
||||
|
||||
/--
|
||||
Store the `range` and `selectionRange` for `declName` where `stx` is the whole syntax object describing `declName`.
|
||||
This method is for the builtin declarations only.
|
||||
User-defined commands should use `Lean.addDeclarationRanges` to store this information for their commands. -/
|
||||
def addDeclarationRanges [Monad m] [MonadEnv m] [MonadFileMap m] (declName : Name) (stx : Syntax) : m Unit := do
|
||||
if stx.getKind == ``Parser.Command.«example» then
|
||||
Stores the `range` and `selectionRange` for `declName` where `modsStx` is the modifier part and
|
||||
`cmdStx` the remaining part of the syntax tree for `declName`.
|
||||
|
||||
This method is for the builtin declarations only. User-defined commands should use
|
||||
`Lean.addDeclarationRanges` to store this information for their commands.
|
||||
-/
|
||||
def addDeclarationRanges [Monad m] [MonadEnv m] [MonadFileMap m] (declName : Name)
|
||||
(modsStx : TSyntax ``Parser.Command.declModifiers) (declStx : Syntax) : m Unit := do
|
||||
if declStx.getKind == ``Parser.Command.«example» then
|
||||
return ()
|
||||
else
|
||||
Lean.addDeclarationRanges declName {
|
||||
range := (← getDeclarationRange stx)
|
||||
selectionRange := (← getDeclarationRange (getDeclarationSelectionRef stx))
|
||||
}
|
||||
let stx := mkNullNode #[modsStx, declStx]
|
||||
-- may fail on partial syntax, ignore in that case
|
||||
let some range ← getDeclarationRange? stx | return
|
||||
let some selectionRange ← getDeclarationRange? (getDeclarationSelectionRef declStx) | return
|
||||
Lean.addDeclarationRanges declName { range, selectionRange }
|
||||
|
||||
/-- Auxiliary method for recording ranges for auxiliary declarations (e.g., fields, nested declarations, etc. -/
|
||||
def addAuxDeclarationRanges [Monad m] [MonadEnv m] [MonadFileMap m] (declName : Name) (stx : Syntax) (header : Syntax) : m Unit := do
|
||||
Lean.addDeclarationRanges declName {
|
||||
range := (← getDeclarationRange stx)
|
||||
selectionRange := (← getDeclarationRange header)
|
||||
}
|
||||
-- may fail on partial syntax, ignore in that case
|
||||
let some range ← getDeclarationRange? stx | return
|
||||
let some selectionRange ← getDeclarationRange? header | return
|
||||
Lean.addDeclarationRanges declName { range, selectionRange }
|
||||
|
||||
end Lean.Elab
|
||||
|
||||
@@ -102,7 +102,7 @@ partial def IO.processCommandsIncrementally (inputCtx : Parser.InputContext)
|
||||
where
|
||||
go initialSnap t commands :=
|
||||
let snap := t.get
|
||||
let commands := commands.push snap.data.stx
|
||||
let commands := commands.push snap.data
|
||||
if let some next := snap.nextCmdSnap? then
|
||||
go initialSnap next.task commands
|
||||
else
|
||||
@@ -111,13 +111,15 @@ where
|
||||
let messages := toSnapshotTree initialSnap
|
||||
|>.getAll.map (·.diagnostics.msgLog)
|
||||
|>.foldl (· ++ ·) {}
|
||||
let trees := toSnapshotTree initialSnap
|
||||
|>.getAll.map (·.infoTree?) |>.filterMap id |>.toPArray'
|
||||
-- In contrast to messages, we should collect info trees only from the top-level command
|
||||
-- snapshots as they subsume any info trees reported incrementally by their children.
|
||||
let trees := commands.map (·.finishedSnap.get.infoTree?) |>.filterMap id |>.toPArray'
|
||||
return {
|
||||
commandState := { snap.data.finishedSnap.get.cmdState with messages, infoState.trees := trees }
|
||||
parserState := snap.data.parserState
|
||||
cmdPos := snap.data.parserState.pos
|
||||
inputCtx, initialSnap, commands
|
||||
commands := commands.map (·.stx)
|
||||
inputCtx, initialSnap
|
||||
}
|
||||
|
||||
def IO.processCommands (inputCtx : Parser.InputContext) (parserState : Parser.ModuleParserState)
|
||||
|
||||
@@ -90,6 +90,7 @@ private def elabLetRecDeclValues (view : LetRecView) : TermElabM (Array Expr) :=
|
||||
for i in [0:view.binderIds.size] do
|
||||
addLocalVarInfo view.binderIds[i]! xs[i]!
|
||||
withDeclName view.declName do
|
||||
withInfoContext' view.valStx (mkInfo := mkTermInfo `MutualDef.body view.valStx) do
|
||||
let value ← elabTermEnsuringType view.valStx type
|
||||
mkLambdaFVars xs value
|
||||
|
||||
|
||||
@@ -410,11 +410,15 @@ private def elabFunValues (headers : Array DefViewElabHeader) (vars : Array Expr
|
||||
-- skip auto-bound prefix in `xs`
|
||||
addLocalVarInfo header.binderIds[i] xs[header.numParams - header.binderIds.size + i]!
|
||||
let val ← withReader ({ · with tacSnap? := header.tacSnap? }) do
|
||||
-- synthesize mvars here to force the top-level tactic block (if any) to run
|
||||
elabTermEnsuringType valStx type <* synthesizeSyntheticMVarsNoPostponing
|
||||
-- NOTE: without this `instantiatedMVars`, `mkLambdaFVars` may leave around a redex that
|
||||
-- leads to more section variables being included than necessary
|
||||
let val ← instantiateMVarsProfiling val
|
||||
-- Store instantiated body in info tree for the benefit of the unused variables linter
|
||||
-- and other metaprograms that may want to inspect it without paying for the instantiation
|
||||
-- again
|
||||
withInfoContext' valStx (mkInfo := mkTermInfo `MutualDef.body valStx) do
|
||||
-- synthesize mvars here to force the top-level tactic block (if any) to run
|
||||
let val ← elabTermEnsuringType valStx type <* synthesizeSyntheticMVarsNoPostponing
|
||||
-- NOTE: without this `instantiatedMVars`, `mkLambdaFVars` may leave around a redex that
|
||||
-- leads to more section variables being included than necessary
|
||||
instantiateMVarsProfiling val
|
||||
let val ← mkLambdaFVars xs val
|
||||
if linter.unusedSectionVars.get (← getOptions) && !header.type.hasSorry && !val.hasSorry then
|
||||
let unusedVars ← vars.filterMapM fun var => do
|
||||
@@ -883,6 +887,7 @@ def getKindForLetRecs (mainHeaders : Array DefViewElabHeader) : DefKind :=
|
||||
else DefKind.«def»
|
||||
|
||||
def getModifiersForLetRecs (mainHeaders : Array DefViewElabHeader) : Modifiers := {
|
||||
stx := ⟨mkNullNode #[]⟩ -- ignore when computing declaration range
|
||||
isNoncomputable := mainHeaders.any fun h => h.modifiers.isNoncomputable
|
||||
recKind := if mainHeaders.any fun h => h.modifiers.isPartial then RecKind.partial else RecKind.default
|
||||
isUnsafe := mainHeaders.any fun h => h.modifiers.isUnsafe
|
||||
@@ -993,7 +998,7 @@ where
|
||||
for view in views, header in headers do
|
||||
-- NOTE: this should be the full `ref`, and thus needs to be done after any snapshotting
|
||||
-- that depends only on a part of the ref
|
||||
addDeclarationRanges header.declName view.ref
|
||||
addDeclarationRanges header.declName view.modifiers.stx view.ref
|
||||
|
||||
|
||||
processDeriving (headers : Array DefViewElabHeader) := do
|
||||
@@ -1017,7 +1022,7 @@ def elabMutualDef (ds : Array Syntax) : CommandElabM Unit := do
|
||||
let mut reusedAllHeaders := true
|
||||
for h : i in [0:ds.size], headerPromise in headerPromises do
|
||||
let d := ds[i]
|
||||
let modifiers ← elabModifiers d[0]
|
||||
let modifiers ← elabModifiers ⟨d[0]⟩
|
||||
if ds.size > 1 && modifiers.isNonrec then
|
||||
throwErrorAt d "invalid use of 'nonrec' modifier in 'mutual' block"
|
||||
let mut view ← mkDefView modifiers d[1]
|
||||
|
||||
@@ -221,7 +221,7 @@ def addAndCompilePartialRec (preDefs : Array PreDefinition) : TermElabM Unit :=
|
||||
else
|
||||
none
|
||||
| _ => none
|
||||
modifiers := {} }
|
||||
modifiers := default }
|
||||
|
||||
private def containsRecFn (recFnNames : Array Name) (e : Expr) : Bool :=
|
||||
(e.find? fun e => e.isConst && recFnNames.contains e.constName!).isSome
|
||||
|
||||
@@ -212,21 +212,21 @@ def mkBRecOnMotive (recArgInfo : RecArgInfo) (value : Expr) : M Expr := do
|
||||
/--
|
||||
Calculates the `.brecOn` functional argument corresponding to one structural recursive function.
|
||||
The `value` is the function with (only) the fixed parameters moved into the context,
|
||||
The `type` is the expected type of the argument.
|
||||
The `FType` is the expected type of the argument.
|
||||
The `recArgInfos` is used to transform the body of the function to replace recursive calls with
|
||||
uses of the `below` induction hypothesis.
|
||||
-/
|
||||
def mkBRecOnF (recArgInfos : Array RecArgInfo) (positions : Positions)
|
||||
(recArgInfo : RecArgInfo) (value : Expr) (FType : Expr) : M Expr := do
|
||||
lambdaTelescope value fun xs value => do
|
||||
let (indexMajorArgs, otherArgs) := recArgInfo.pickIndicesMajor xs
|
||||
let FType ← instantiateForall FType indexMajorArgs
|
||||
let (indicesMajorArgs, otherArgs) := recArgInfo.pickIndicesMajor xs
|
||||
let FType ← instantiateForall FType indicesMajorArgs
|
||||
forallBoundedTelescope FType (some 1) fun below _ => do
|
||||
-- TODO: `below` user name is `f`, and it will make a global `f` to be pretty printed as `_root_.f` in error messages.
|
||||
-- We should add an option to `forallBoundedTelescope` to ensure fresh names are used.
|
||||
let below := below[0]!
|
||||
let valueNew ← replaceRecApps recArgInfos positions below value
|
||||
mkLambdaFVars (indexMajorArgs ++ #[below] ++ otherArgs) valueNew
|
||||
let valueNew ← replaceRecApps recArgInfos positions below value
|
||||
mkLambdaFVars (indicesMajorArgs ++ #[below] ++ otherArgs) valueNew
|
||||
|
||||
/--
|
||||
Given the `motives`, figures out whether to use `.brecOn` or `.binductionOn`, pass
|
||||
@@ -264,7 +264,7 @@ def inferBRecOnFTypes (recArgInfos : Array RecArgInfo) (positions : Positions)
|
||||
(brecOnConst : Nat → Expr) : MetaM (Array Expr) := do
|
||||
let numTypeFormers := positions.size
|
||||
let recArgInfo := recArgInfos[0]! -- pick an arbitrary one
|
||||
let brecOn := brecOnConst 0
|
||||
let brecOn := brecOnConst recArgInfo.indIdx
|
||||
check brecOn
|
||||
let brecOnType ← inferType brecOn
|
||||
-- Skip the indices and major argument
|
||||
|
||||
@@ -77,7 +77,7 @@ def getRecArgInfo (fnName : Name) (numFixed : Nat) (xs : Array Expr) (i : Nat) :
|
||||
if !indIndices.all Expr.isFVar then
|
||||
throwError "its type {indInfo.name} is an inductive family and indices are not variables{indentExpr xType}"
|
||||
else if !indIndices.allDiff then
|
||||
throwError " its type {indInfo.name} is an inductive family and indices are not pairwise distinct{indentExpr xType}"
|
||||
throwError "its type {indInfo.name} is an inductive family and indices are not pairwise distinct{indentExpr xType}"
|
||||
else
|
||||
let indexMinPos := getIndexMinPos xs indIndices
|
||||
let numFixed := if indexMinPos < numFixed then indexMinPos else numFixed
|
||||
|
||||
@@ -107,9 +107,9 @@ private def elimMutualRecursion (preDefs : Array PreDefinition) (xs : Array Expr
|
||||
check valueNew
|
||||
return #[{ preDef with value := valueNew }]
|
||||
|
||||
-- Sort the (indices of the) definitions by their position in indInfo.all
|
||||
-- Groups the (indices of the) definitions by their position in indInfo.all
|
||||
let positions : Positions := .groupAndSort (·.indIdx) recArgInfos (Array.range indInfo.numTypeFormers)
|
||||
trace[Elab.definition.structural] "positions: {positions}"
|
||||
trace[Elab.definition.structural] "assignments of type formers of {indInfo.name} to functions: {positions}"
|
||||
|
||||
-- Construct the common `.brecOn` arguments
|
||||
let motives ← (Array.zip recArgInfos values).mapM fun (r, v) => mkBRecOnMotive r v
|
||||
@@ -117,7 +117,7 @@ private def elimMutualRecursion (preDefs : Array PreDefinition) (xs : Array Expr
|
||||
let brecOnConst ← mkBRecOnConst recArgInfos positions motives
|
||||
let FTypes ← inferBRecOnFTypes recArgInfos positions brecOnConst
|
||||
trace[Elab.definition.structural] "FTypes: {FTypes}"
|
||||
let FArgs ← (recArgInfos.zip (values.zip FTypes)).mapM fun (r, (v, t)) =>
|
||||
let FArgs ← (recArgInfos.zip (values.zip FTypes)).mapM fun (r, (v, t)) =>
|
||||
mkBRecOnF recArgInfos positions r v t
|
||||
trace[Elab.definition.structural] "FArgs: {FArgs}"
|
||||
-- Assemble the individual `.brecOn` applications
|
||||
|
||||
@@ -15,7 +15,7 @@ partial def addSmartUnfoldingDefAux (preDef : PreDefinition) (recArgPos : Nat) :
|
||||
return { preDef with
|
||||
declName := mkSmartUnfoldingNameFor preDef.declName
|
||||
value := (← visit preDef.value)
|
||||
modifiers := {}
|
||||
modifiers := default
|
||||
}
|
||||
where
|
||||
/--
|
||||
|
||||
@@ -95,7 +95,7 @@ private def expandCtor (structStx : Syntax) (structModifiers : Modifiers) (struc
|
||||
let declName := structDeclName ++ defaultCtorName
|
||||
let ref := structStx[1].mkSynthetic
|
||||
addAuxDeclarationRanges declName ref ref
|
||||
pure { ref, modifiers := {}, name := defaultCtorName, declName }
|
||||
pure { ref, modifiers := default, name := defaultCtorName, declName }
|
||||
if structStx[5].isNone then
|
||||
useDefault
|
||||
else
|
||||
@@ -912,7 +912,7 @@ def elabStructure (modifiers : Modifiers) (stx : Syntax) : CommandElabM Unit :=
|
||||
let scopeLevelNames ← Term.getLevelNames
|
||||
let ⟨name, declName, allUserLevelNames⟩ ← Elab.expandDeclId (← getCurrNamespace) scopeLevelNames declId modifiers
|
||||
Term.withAutoBoundImplicitForbiddenPred (fun n => name == n) do
|
||||
addDeclarationRanges declName stx
|
||||
addDeclarationRanges declName modifiers.stx stx
|
||||
Term.withDeclName declName do
|
||||
let ctor ← expandCtor stx modifiers declName
|
||||
let fields ← expandFields stx modifiers declName
|
||||
|
||||
@@ -65,202 +65,218 @@ def getNatOrBvValue? (ty : Expr) (expr : Expr) : M (Option Nat) := do
|
||||
| _ => return none
|
||||
|
||||
/--
|
||||
Reify an `Expr` that's a `BitVec`.
|
||||
Construct an uninterpreted `BitVec` atom from `x`.
|
||||
-/
|
||||
def bitVecAtom (x : Expr) : 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
|
||||
return some atom
|
||||
|
||||
/--
|
||||
Reify an `Expr` that's a constant-width `BitVec`.
|
||||
Unless this function is called on something that is not a constant-width `BitVec` it is always
|
||||
going to return `some`.
|
||||
-/
|
||||
partial def of (x : Expr) : M (Option ReifiedBVExpr) := do
|
||||
match_expr x with
|
||||
| BitVec.ofNat _ _ => goBvLit x
|
||||
| HAnd.hAnd _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .and ``Std.Tactic.BVDecide.Reflect.BitVec.and_congr
|
||||
| HOr.hOr _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .or ``Std.Tactic.BVDecide.Reflect.BitVec.or_congr
|
||||
| HXor.hXor _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .xor ``Std.Tactic.BVDecide.Reflect.BitVec.xor_congr
|
||||
| HAdd.hAdd _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .add ``Std.Tactic.BVDecide.Reflect.BitVec.add_congr
|
||||
| HMul.hMul _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .mul ``Std.Tactic.BVDecide.Reflect.BitVec.mul_congr
|
||||
| HDiv.hDiv _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .udiv ``Std.Tactic.BVDecide.Reflect.BitVec.udiv_congr
|
||||
| HMod.hMod _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .umod ``Std.Tactic.BVDecide.Reflect.BitVec.umod_congr
|
||||
| Complement.complement _ _ innerExpr =>
|
||||
unaryReflection innerExpr .not ``Std.Tactic.BVDecide.Reflect.BitVec.not_congr
|
||||
| HShiftLeft.hShiftLeft _ β _ _ innerExpr distanceExpr =>
|
||||
let distance? ← getNatOrBvValue? β distanceExpr
|
||||
if distance?.isSome then
|
||||
shiftConstReflection
|
||||
β
|
||||
distanceExpr
|
||||
goOrAtom x
|
||||
where
|
||||
/--
|
||||
Reify `x`, returns `none` if the reification procedure failed.
|
||||
-/
|
||||
go (x : Expr) : M (Option ReifiedBVExpr) := do
|
||||
match_expr x with
|
||||
| BitVec.ofNat _ _ => goBvLit x
|
||||
| HAnd.hAnd _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .and ``Std.Tactic.BVDecide.Reflect.BitVec.and_congr
|
||||
| HOr.hOr _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .or ``Std.Tactic.BVDecide.Reflect.BitVec.or_congr
|
||||
| HXor.hXor _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .xor ``Std.Tactic.BVDecide.Reflect.BitVec.xor_congr
|
||||
| HAdd.hAdd _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .add ``Std.Tactic.BVDecide.Reflect.BitVec.add_congr
|
||||
| HMul.hMul _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .mul ``Std.Tactic.BVDecide.Reflect.BitVec.mul_congr
|
||||
| HDiv.hDiv _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .udiv ``Std.Tactic.BVDecide.Reflect.BitVec.udiv_congr
|
||||
| HMod.hMod _ _ _ _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .umod ``Std.Tactic.BVDecide.Reflect.BitVec.umod_congr
|
||||
| Complement.complement _ _ innerExpr =>
|
||||
unaryReflection innerExpr .not ``Std.Tactic.BVDecide.Reflect.BitVec.not_congr
|
||||
| HShiftLeft.hShiftLeft _ β _ _ innerExpr distanceExpr =>
|
||||
let distance? ← getNatOrBvValue? β distanceExpr
|
||||
if distance?.isSome then
|
||||
shiftConstReflection
|
||||
β
|
||||
distanceExpr
|
||||
innerExpr
|
||||
.shiftLeftConst
|
||||
``BVUnOp.shiftLeftConst
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.shiftLeftNat_congr
|
||||
else
|
||||
shiftReflection
|
||||
β
|
||||
distanceExpr
|
||||
innerExpr
|
||||
.shiftLeft
|
||||
``BVExpr.shiftLeft
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.shiftLeft_congr
|
||||
| HShiftRight.hShiftRight _ β _ _ innerExpr distanceExpr =>
|
||||
let distance? ← getNatOrBvValue? β distanceExpr
|
||||
if distance?.isSome then
|
||||
shiftConstReflection
|
||||
β
|
||||
distanceExpr
|
||||
innerExpr
|
||||
.shiftRightConst
|
||||
``BVUnOp.shiftRightConst
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.shiftRightNat_congr
|
||||
else
|
||||
shiftReflection
|
||||
β
|
||||
distanceExpr
|
||||
innerExpr
|
||||
.shiftRight
|
||||
``BVExpr.shiftRight
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.shiftRight_congr
|
||||
| BitVec.sshiftRight _ innerExpr distanceExpr =>
|
||||
let some distance ← getNatValue? distanceExpr | return none
|
||||
shiftConstLikeReflection
|
||||
distance
|
||||
innerExpr
|
||||
.shiftLeftConst
|
||||
``BVUnOp.shiftLeftConst
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.shiftLeftNat_congr
|
||||
else
|
||||
shiftReflection
|
||||
β
|
||||
distanceExpr
|
||||
innerExpr
|
||||
.shiftLeft
|
||||
``BVExpr.shiftLeft
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.shiftLeft_congr
|
||||
| HShiftRight.hShiftRight _ β _ _ innerExpr distanceExpr =>
|
||||
let distance? ← getNatOrBvValue? β distanceExpr
|
||||
if distance?.isSome then
|
||||
shiftConstReflection
|
||||
β
|
||||
distanceExpr
|
||||
innerExpr
|
||||
.shiftRightConst
|
||||
``BVUnOp.shiftRightConst
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.shiftRightNat_congr
|
||||
else
|
||||
shiftReflection
|
||||
β
|
||||
distanceExpr
|
||||
innerExpr
|
||||
.shiftRight
|
||||
``BVExpr.shiftRight
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.shiftRight_congr
|
||||
| BitVec.sshiftRight _ innerExpr distanceExpr =>
|
||||
let some distance ← getNatValue? distanceExpr | return ← ofAtom x
|
||||
shiftConstLikeReflection
|
||||
distance
|
||||
innerExpr
|
||||
.arithShiftRightConst
|
||||
``BVUnOp.arithShiftRightConst
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.arithShiftRight_congr
|
||||
| BitVec.zeroExtend _ newWidthExpr innerExpr =>
|
||||
let some newWidth ← getNatValue? newWidthExpr | return ← ofAtom x
|
||||
let some inner ← ofOrAtom innerExpr | return none
|
||||
let bvExpr := .zeroExtend newWidth inner.bvExpr
|
||||
let expr :=
|
||||
mkApp3
|
||||
(mkConst ``BVExpr.zeroExtend)
|
||||
.arithShiftRightConst
|
||||
``BVUnOp.arithShiftRightConst
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.arithShiftRight_congr
|
||||
| BitVec.zeroExtend _ newWidthExpr innerExpr =>
|
||||
let some newWidth ← getNatValue? newWidthExpr | return none
|
||||
let some inner ← goOrAtom innerExpr | return none
|
||||
let bvExpr := .zeroExtend newWidth inner.bvExpr
|
||||
let expr :=
|
||||
mkApp3
|
||||
(mkConst ``BVExpr.zeroExtend)
|
||||
(toExpr inner.width)
|
||||
newWidthExpr
|
||||
inner.expr
|
||||
let proof := do
|
||||
let innerEval ← mkEvalExpr inner.width inner.expr
|
||||
let innerProof ← inner.evalsAtAtoms
|
||||
return mkApp5 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.zeroExtend_congr)
|
||||
newWidthExpr
|
||||
(toExpr inner.width)
|
||||
innerExpr
|
||||
innerEval
|
||||
innerProof
|
||||
return some ⟨newWidth, bvExpr, proof, expr⟩
|
||||
| BitVec.signExtend _ newWidthExpr innerExpr =>
|
||||
let some newWidth ← getNatValue? newWidthExpr | return none
|
||||
let some inner ← goOrAtom innerExpr | return none
|
||||
let bvExpr := .signExtend newWidth inner.bvExpr
|
||||
let expr :=
|
||||
mkApp3
|
||||
(mkConst ``BVExpr.signExtend)
|
||||
(toExpr inner.width)
|
||||
newWidthExpr
|
||||
inner.expr
|
||||
let proof := do
|
||||
let innerEval ← mkEvalExpr inner.width inner.expr
|
||||
let innerProof ← inner.evalsAtAtoms
|
||||
return mkApp5 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.signExtend_congr)
|
||||
newWidthExpr
|
||||
(toExpr inner.width)
|
||||
innerExpr
|
||||
innerEval
|
||||
innerProof
|
||||
return some ⟨newWidth, bvExpr, proof, expr⟩
|
||||
| HAppend.hAppend _ _ _ _ lhsExpr rhsExpr =>
|
||||
let some lhs ← goOrAtom lhsExpr | return none
|
||||
let some rhs ← goOrAtom rhsExpr | return none
|
||||
let bvExpr := .append lhs.bvExpr rhs.bvExpr
|
||||
let expr := mkApp4 (mkConst ``BVExpr.append)
|
||||
(toExpr lhs.width)
|
||||
(toExpr rhs.width)
|
||||
lhs.expr rhs.expr
|
||||
let proof := do
|
||||
let lhsEval ← mkEvalExpr lhs.width lhs.expr
|
||||
let lhsProof ← lhs.evalsAtAtoms
|
||||
let rhsProof ← rhs.evalsAtAtoms
|
||||
let rhsEval ← mkEvalExpr rhs.width rhs.expr
|
||||
return mkApp8 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.append_congr)
|
||||
(toExpr lhs.width) (toExpr rhs.width)
|
||||
lhsExpr lhsEval
|
||||
rhsExpr rhsEval
|
||||
lhsProof rhsProof
|
||||
return some ⟨lhs.width + rhs.width, bvExpr, proof, expr⟩
|
||||
| BitVec.replicate _ nExpr innerExpr =>
|
||||
let some inner ← goOrAtom innerExpr | return none
|
||||
let some n ← getNatValue? nExpr | return none
|
||||
let bvExpr := .replicate n inner.bvExpr
|
||||
let expr := mkApp3 (mkConst ``BVExpr.replicate)
|
||||
(toExpr inner.width)
|
||||
newWidthExpr
|
||||
inner.expr
|
||||
let proof := do
|
||||
let innerEval ← mkEvalExpr inner.width inner.expr
|
||||
let innerProof ← inner.evalsAtAtoms
|
||||
return mkApp5 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.zeroExtend_congr)
|
||||
newWidthExpr
|
||||
(toExpr inner.width)
|
||||
innerExpr
|
||||
innerEval
|
||||
innerProof
|
||||
return some ⟨newWidth, bvExpr, proof, expr⟩
|
||||
| BitVec.signExtend _ newWidthExpr innerExpr =>
|
||||
let some newWidth ← getNatValue? newWidthExpr | return ← ofAtom x
|
||||
let some inner ← ofOrAtom innerExpr | return none
|
||||
let bvExpr := .signExtend newWidth inner.bvExpr
|
||||
let expr :=
|
||||
mkApp3
|
||||
(mkConst ``BVExpr.signExtend)
|
||||
(toExpr inner.width)
|
||||
newWidthExpr
|
||||
inner.expr
|
||||
let proof := do
|
||||
let innerEval ← mkEvalExpr inner.width inner.expr
|
||||
let innerProof ← inner.evalsAtAtoms
|
||||
return mkApp5 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.signExtend_congr)
|
||||
newWidthExpr
|
||||
(toExpr inner.width)
|
||||
innerExpr
|
||||
innerEval
|
||||
innerProof
|
||||
return some ⟨newWidth, bvExpr, proof, expr⟩
|
||||
| HAppend.hAppend _ _ _ _ lhsExpr rhsExpr =>
|
||||
let some lhs ← ofOrAtom lhsExpr | return none
|
||||
let some rhs ← ofOrAtom rhsExpr | return none
|
||||
let bvExpr := .append lhs.bvExpr rhs.bvExpr
|
||||
let expr := mkApp4 (mkConst ``BVExpr.append)
|
||||
(toExpr lhs.width)
|
||||
(toExpr rhs.width)
|
||||
lhs.expr rhs.expr
|
||||
let proof := do
|
||||
let lhsEval ← mkEvalExpr lhs.width lhs.expr
|
||||
let lhsProof ← lhs.evalsAtAtoms
|
||||
let rhsProof ← rhs.evalsAtAtoms
|
||||
let rhsEval ← mkEvalExpr rhs.width rhs.expr
|
||||
return mkApp8 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.append_congr)
|
||||
(toExpr lhs.width) (toExpr rhs.width)
|
||||
lhsExpr lhsEval
|
||||
rhsExpr rhsEval
|
||||
lhsProof rhsProof
|
||||
return some ⟨lhs.width + rhs.width, bvExpr, proof, expr⟩
|
||||
| BitVec.replicate _ nExpr innerExpr =>
|
||||
let some inner ← ofOrAtom innerExpr | return none
|
||||
let some n ← getNatValue? nExpr | return ← ofAtom x
|
||||
let bvExpr := .replicate n inner.bvExpr
|
||||
let expr := mkApp3 (mkConst ``BVExpr.replicate)
|
||||
(toExpr inner.width)
|
||||
(toExpr n)
|
||||
inner.expr
|
||||
let proof := do
|
||||
let innerEval ← mkEvalExpr inner.width inner.expr
|
||||
let innerProof ← inner.evalsAtAtoms
|
||||
return mkApp5 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.replicate_congr)
|
||||
(toExpr n)
|
||||
inner.expr
|
||||
let proof := do
|
||||
let innerEval ← mkEvalExpr inner.width inner.expr
|
||||
let innerProof ← inner.evalsAtAtoms
|
||||
return mkApp5 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.replicate_congr)
|
||||
(toExpr n)
|
||||
(toExpr inner.width)
|
||||
innerExpr
|
||||
innerEval
|
||||
innerProof
|
||||
return some ⟨inner.width * n, bvExpr, proof, expr⟩
|
||||
| BitVec.extractLsb' _ startExpr lenExpr innerExpr =>
|
||||
let some start ← getNatValue? startExpr | return none
|
||||
let some len ← getNatValue? lenExpr | return none
|
||||
let some inner ← goOrAtom innerExpr | return none
|
||||
let bvExpr := .extract start len inner.bvExpr
|
||||
let expr := mkApp4 (mkConst ``BVExpr.extract)
|
||||
(toExpr inner.width)
|
||||
innerExpr
|
||||
innerEval
|
||||
innerProof
|
||||
return some ⟨inner.width * n, bvExpr, proof, expr⟩
|
||||
| BitVec.extractLsb' _ startExpr lenExpr innerExpr =>
|
||||
let some start ← getNatValue? startExpr | return ← ofAtom x
|
||||
let some len ← getNatValue? lenExpr | return ← ofAtom x
|
||||
let some inner ← ofOrAtom innerExpr | return none
|
||||
let bvExpr := .extract start len inner.bvExpr
|
||||
let expr := mkApp4 (mkConst ``BVExpr.extract)
|
||||
(toExpr inner.width)
|
||||
startExpr
|
||||
lenExpr
|
||||
inner.expr
|
||||
let proof := do
|
||||
let innerEval ← mkEvalExpr inner.width inner.expr
|
||||
let innerProof ← inner.evalsAtAtoms
|
||||
return mkApp6 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.extract_congr)
|
||||
startExpr
|
||||
lenExpr
|
||||
(toExpr inner.width)
|
||||
inner.expr
|
||||
let proof := do
|
||||
let innerEval ← mkEvalExpr inner.width inner.expr
|
||||
let innerProof ← inner.evalsAtAtoms
|
||||
return mkApp6 (mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.extract_congr)
|
||||
startExpr
|
||||
lenExpr
|
||||
(toExpr inner.width)
|
||||
innerExpr
|
||||
innerEval
|
||||
innerProof
|
||||
return some ⟨len, bvExpr, proof, expr⟩
|
||||
| BitVec.rotateLeft _ innerExpr distanceExpr =>
|
||||
rotateReflection
|
||||
distanceExpr
|
||||
innerExpr
|
||||
innerEval
|
||||
innerProof
|
||||
return some ⟨len, bvExpr, proof, expr⟩
|
||||
| BitVec.rotateLeft _ innerExpr distanceExpr =>
|
||||
rotateReflection
|
||||
distanceExpr
|
||||
innerExpr
|
||||
.rotateLeft
|
||||
``BVUnOp.rotateLeft
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.rotateLeft_congr
|
||||
| BitVec.rotateRight _ innerExpr distanceExpr =>
|
||||
rotateReflection
|
||||
distanceExpr
|
||||
innerExpr
|
||||
.rotateRight
|
||||
``BVUnOp.rotateRight
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.rotateRight_congr
|
||||
| _ => ofAtom x
|
||||
where
|
||||
ofAtom (x : Expr) : 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
|
||||
return some atom
|
||||
.rotateLeft
|
||||
``BVUnOp.rotateLeft
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.rotateLeft_congr
|
||||
| BitVec.rotateRight _ innerExpr distanceExpr =>
|
||||
rotateReflection
|
||||
distanceExpr
|
||||
innerExpr
|
||||
.rotateRight
|
||||
``BVUnOp.rotateRight
|
||||
``Std.Tactic.BVDecide.Reflect.BitVec.rotateRight_congr
|
||||
| _ => return none
|
||||
|
||||
ofOrAtom (x : Expr) : M (Option ReifiedBVExpr) := do
|
||||
let res ← of x
|
||||
/--
|
||||
Reify `x` or abstract it as an atom.
|
||||
Unless this function is called on something that is not a fixed-width `BitVec` it is always going
|
||||
to return `some`.
|
||||
-/
|
||||
goOrAtom (x : Expr) : M (Option ReifiedBVExpr) := do
|
||||
let res ← go x
|
||||
match res with
|
||||
| some exp => return some exp
|
||||
| none => ofAtom x
|
||||
| none => bitVecAtom x
|
||||
|
||||
shiftConstLikeReflection (distance : Nat) (innerExpr : Expr) (shiftOp : Nat → BVUnOp)
|
||||
(shiftOpName : Name) (congrThm : Name) :
|
||||
M (Option ReifiedBVExpr) := do
|
||||
let some inner ← ofOrAtom innerExpr | return none
|
||||
let some inner ← goOrAtom innerExpr | return none
|
||||
let bvExpr : BVExpr inner.width := .un (shiftOp distance) inner.bvExpr
|
||||
let expr :=
|
||||
mkApp3
|
||||
@@ -278,24 +294,22 @@ where
|
||||
rotateReflection (distanceExpr : Expr) (innerExpr : Expr) (rotateOp : Nat → BVUnOp)
|
||||
(rotateOpName : Name) (congrThm : Name) :
|
||||
M (Option ReifiedBVExpr) := do
|
||||
-- Either the shift values are constant or we abstract the entire term as atoms
|
||||
let some distance ← getNatValue? distanceExpr | return ← ofAtom x
|
||||
let some distance ← getNatValue? distanceExpr | return none
|
||||
shiftConstLikeReflection distance innerExpr rotateOp rotateOpName congrThm
|
||||
|
||||
shiftConstReflection (β : Expr) (distanceExpr : Expr) (innerExpr : Expr) (shiftOp : Nat → BVUnOp)
|
||||
(shiftOpName : Name) (congrThm : Name) :
|
||||
M (Option ReifiedBVExpr) := do
|
||||
-- Either the shift values are constant or we abstract the entire term as atoms
|
||||
let some distance ← getNatOrBvValue? β distanceExpr | return ← ofAtom x
|
||||
let some distance ← getNatOrBvValue? β distanceExpr | return none
|
||||
shiftConstLikeReflection distance innerExpr shiftOp shiftOpName congrThm
|
||||
|
||||
shiftReflection (β : Expr) (distanceExpr : Expr) (innerExpr : Expr)
|
||||
(shiftOp : {m n : Nat} → BVExpr m → BVExpr n → BVExpr m) (shiftOpName : Name)
|
||||
(congrThm : Name) :
|
||||
M (Option ReifiedBVExpr) := do
|
||||
let_expr BitVec _ ← β | return ← ofAtom x
|
||||
let some inner ← of innerExpr | return none
|
||||
let some distance ← of distanceExpr | return none
|
||||
let_expr BitVec _ ← β | return none
|
||||
let some inner ← goOrAtom innerExpr | return none
|
||||
let some distance ← goOrAtom distanceExpr | return none
|
||||
let bvExpr : BVExpr inner.width := shiftOp inner.bvExpr distance.bvExpr
|
||||
let expr :=
|
||||
mkApp4
|
||||
@@ -314,8 +328,8 @@ where
|
||||
|
||||
binaryReflection (lhsExpr rhsExpr : Expr) (op : BVBinOp) (congrThm : Name) :
|
||||
M (Option ReifiedBVExpr) := do
|
||||
let some lhs ← ofOrAtom lhsExpr | return none
|
||||
let some rhs ← ofOrAtom rhsExpr | return none
|
||||
let some lhs ← goOrAtom lhsExpr | return none
|
||||
let some rhs ← goOrAtom rhsExpr | return none
|
||||
if h : rhs.width = lhs.width then
|
||||
let bvExpr : BVExpr lhs.width := .bin lhs.bvExpr op (h ▸ rhs.bvExpr)
|
||||
let expr := mkApp4 (mkConst ``BVExpr.bin) (toExpr lhs.width) lhs.expr (toExpr op) rhs.expr
|
||||
@@ -335,7 +349,7 @@ where
|
||||
|
||||
unaryReflection (innerExpr : Expr) (op : BVUnOp) (congrThm : Name) :
|
||||
M (Option ReifiedBVExpr) := do
|
||||
let some inner ← ofOrAtom innerExpr | return none
|
||||
let some inner ← goOrAtom innerExpr | return none
|
||||
let bvExpr := .un op inner.bvExpr
|
||||
let expr := mkApp3 (mkConst ``BVExpr.un) (toExpr inner.width) (toExpr op) inner.expr
|
||||
let proof := unaryCongrProof inner innerExpr (mkConst congrThm)
|
||||
@@ -347,7 +361,7 @@ where
|
||||
return mkApp4 congrProof (toExpr inner.width) innerExpr innerEval innerProof
|
||||
|
||||
goBvLit (x : Expr) : M (Option ReifiedBVExpr) := do
|
||||
let some ⟨width, bvVal⟩ ← getBitVecValue? x | return ← ofAtom x
|
||||
let some ⟨width, bvVal⟩ ← getBitVecValue? x | return ← bitVecAtom x
|
||||
let bvExpr : BVExpr width := .const bvVal
|
||||
let expr := mkApp2 (mkConst ``BVExpr.const) (toExpr width) (toExpr bvVal)
|
||||
let proof := do
|
||||
|
||||
@@ -44,40 +44,75 @@ def mkTrans (x y z : Expr) (hxy hyz : Expr) : Expr :=
|
||||
def mkEvalExpr (expr : Expr) : M Expr := do
|
||||
return mkApp2 (mkConst ``BVLogicalExpr.eval) (← M.atomsAssignment) expr
|
||||
|
||||
/--
|
||||
Construct a `ReifiedBVLogical` from `ReifiedBVPred` by wrapping it as an atom.
|
||||
-/
|
||||
def ofPred (bvPred : ReifiedBVPred) : M (Option ReifiedBVLogical) := do
|
||||
let boolExpr := .literal bvPred.bvPred
|
||||
let expr := mkApp2 (mkConst ``BoolExpr.literal) (mkConst ``BVPred) bvPred.expr
|
||||
let proof := bvPred.evalsAtAtoms
|
||||
return some ⟨boolExpr, proof, expr⟩
|
||||
|
||||
/--
|
||||
Construct an uninterrpeted `Bool` atom from `t`.
|
||||
-/
|
||||
def boolAtom (t : Expr) : M (Option ReifiedBVLogical) := do
|
||||
let some pred ← ReifiedBVPred.boolAtom t | return none
|
||||
ofPred pred
|
||||
|
||||
/--
|
||||
Reify an `Expr` that is a boolean expression containing predicates about `BitVec` as atoms.
|
||||
Unless this function is called on something that is not a `Bool` it is always going to return `some`.
|
||||
-/
|
||||
partial def of (t : Expr) : M (Option ReifiedBVLogical) := do
|
||||
match_expr t with
|
||||
| Bool.true =>
|
||||
let boolExpr := .const true
|
||||
let expr := mkApp2 (mkConst ``BoolExpr.const) (mkConst ``BVPred) (toExpr Bool.true)
|
||||
let proof := return mkRefl (mkConst ``Bool.true)
|
||||
return some ⟨boolExpr, proof, expr⟩
|
||||
| Bool.false =>
|
||||
let boolExpr := .const false
|
||||
let expr := mkApp2 (mkConst ``BoolExpr.const) (mkConst ``BVPred) (toExpr Bool.false)
|
||||
let proof := return mkRefl (mkConst ``Bool.false)
|
||||
return some ⟨boolExpr, proof, expr⟩
|
||||
| Bool.not subExpr =>
|
||||
let some sub ← of subExpr | return none
|
||||
let boolExpr := .not sub.bvExpr
|
||||
let expr := mkApp2 (mkConst ``BoolExpr.not) (mkConst ``BVPred) sub.expr
|
||||
let proof := do
|
||||
let subEvalExpr ← mkEvalExpr sub.expr
|
||||
let subProof ← sub.evalsAtAtoms
|
||||
return mkApp3 (mkConst ``Std.Tactic.BVDecide.Reflect.Bool.not_congr) subExpr subEvalExpr subProof
|
||||
return some ⟨boolExpr, proof, expr⟩
|
||||
| Bool.and lhsExpr rhsExpr => gateReflection lhsExpr rhsExpr .and ``Std.Tactic.BVDecide.Reflect.Bool.and_congr
|
||||
| Bool.xor lhsExpr rhsExpr => gateReflection lhsExpr rhsExpr .xor ``Std.Tactic.BVDecide.Reflect.Bool.xor_congr
|
||||
| BEq.beq α _ lhsExpr rhsExpr =>
|
||||
match_expr α with
|
||||
| Bool => gateReflection lhsExpr rhsExpr .beq ``Std.Tactic.BVDecide.Reflect.Bool.beq_congr
|
||||
| BitVec _ => goPred t
|
||||
| _ => return none
|
||||
| _ => goPred t
|
||||
goOrAtom t
|
||||
where
|
||||
/--
|
||||
Reify `t`, returns `none` if the reification procedure failed.
|
||||
-/
|
||||
go (t : Expr) : M (Option ReifiedBVLogical) := do
|
||||
match_expr t with
|
||||
| Bool.true =>
|
||||
let boolExpr := .const true
|
||||
let expr := mkApp2 (mkConst ``BoolExpr.const) (mkConst ``BVPred) (toExpr Bool.true)
|
||||
let proof := pure <| mkRefl (mkConst ``Bool.true)
|
||||
return some ⟨boolExpr, proof, expr⟩
|
||||
| Bool.false =>
|
||||
let boolExpr := .const false
|
||||
let expr := mkApp2 (mkConst ``BoolExpr.const) (mkConst ``BVPred) (toExpr Bool.false)
|
||||
let proof := pure <| mkRefl (mkConst ``Bool.false)
|
||||
return some ⟨boolExpr, proof, expr⟩
|
||||
| Bool.not subExpr =>
|
||||
let some sub ← goOrAtom subExpr | return none
|
||||
let boolExpr := .not sub.bvExpr
|
||||
let expr := mkApp2 (mkConst ``BoolExpr.not) (mkConst ``BVPred) sub.expr
|
||||
let proof := do
|
||||
let subEvalExpr ← mkEvalExpr sub.expr
|
||||
let subProof ← sub.evalsAtAtoms
|
||||
return mkApp3 (mkConst ``Std.Tactic.BVDecide.Reflect.Bool.not_congr) subExpr subEvalExpr subProof
|
||||
return some ⟨boolExpr, proof, expr⟩
|
||||
| Bool.and lhsExpr rhsExpr => gateReflection lhsExpr rhsExpr .and ``Std.Tactic.BVDecide.Reflect.Bool.and_congr
|
||||
| Bool.xor lhsExpr rhsExpr => gateReflection lhsExpr rhsExpr .xor ``Std.Tactic.BVDecide.Reflect.Bool.xor_congr
|
||||
| BEq.beq α _ lhsExpr rhsExpr =>
|
||||
match_expr α with
|
||||
| Bool => gateReflection lhsExpr rhsExpr .beq ``Std.Tactic.BVDecide.Reflect.Bool.beq_congr
|
||||
| BitVec _ => goPred t
|
||||
| _ => return none
|
||||
| _ => goPred t
|
||||
|
||||
/--
|
||||
Reify `t` or abstract it as an atom.
|
||||
Unless this function is called on something that is not a `Bool` it is always going to return `some`.
|
||||
-/
|
||||
goOrAtom (t : Expr) : M (Option ReifiedBVLogical) := do
|
||||
match ← go t with
|
||||
| some boolExpr => return some boolExpr
|
||||
| none => boolAtom t
|
||||
|
||||
gateReflection (lhsExpr rhsExpr : Expr) (gate : Gate) (congrThm : Name) :
|
||||
M (Option ReifiedBVLogical) := do
|
||||
let some lhs ← of lhsExpr | return none
|
||||
let some rhs ← of rhsExpr | return none
|
||||
let some lhs ← goOrAtom lhsExpr | return none
|
||||
let some rhs ← goOrAtom rhsExpr | return none
|
||||
let boolExpr := .gate gate lhs.bvExpr rhs.bvExpr
|
||||
let expr :=
|
||||
mkApp4
|
||||
@@ -99,11 +134,8 @@ where
|
||||
return some ⟨boolExpr, proof, expr⟩
|
||||
|
||||
goPred (t : Expr) : M (Option ReifiedBVLogical) := do
|
||||
let some bvPred ← ReifiedBVPred.of t | return none
|
||||
let boolExpr := .literal bvPred.bvPred
|
||||
let expr := mkApp2 (mkConst ``BoolExpr.literal) (mkConst ``BVPred) bvPred.expr
|
||||
let proof := bvPred.evalsAtAtoms
|
||||
return some ⟨boolExpr, proof, expr⟩
|
||||
let some pred ← ReifiedBVPred.of t | return none
|
||||
ofPred pred
|
||||
|
||||
end ReifiedBVLogical
|
||||
|
||||
|
||||
@@ -37,54 +37,68 @@ structure ReifiedBVPred where
|
||||
namespace ReifiedBVPred
|
||||
|
||||
/--
|
||||
Reify an `Expr` that is a proof of a predicate about `BitVec`.
|
||||
Construct an uninterpreted `Bool` atom from `t`.
|
||||
-/
|
||||
def of (t : Expr) : M (Option ReifiedBVPred) := do
|
||||
match_expr t with
|
||||
| BEq.beq α _ lhsExpr rhsExpr =>
|
||||
let_expr BitVec _ := α | return none
|
||||
binaryReflection lhsExpr rhsExpr .eq ``Std.Tactic.BVDecide.Reflect.BitVec.beq_congr
|
||||
| BitVec.ult _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .ult ``Std.Tactic.BVDecide.Reflect.BitVec.ult_congr
|
||||
| BitVec.getLsbD _ subExpr idxExpr =>
|
||||
let some sub ← ReifiedBVExpr.of subExpr | return none
|
||||
let some idx ← getNatValue? idxExpr | return none
|
||||
let bvExpr : BVPred := .getLsbD sub.bvExpr idx
|
||||
let expr := mkApp3 (mkConst ``BVPred.getLsbD) (toExpr sub.width) sub.expr idxExpr
|
||||
let proof := do
|
||||
let subEval ← ReifiedBVExpr.mkEvalExpr sub.width sub.expr
|
||||
let subProof ← sub.evalsAtAtoms
|
||||
return mkApp5
|
||||
(mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.getLsbD_congr)
|
||||
idxExpr
|
||||
(toExpr sub.width)
|
||||
subExpr
|
||||
subEval
|
||||
subProof
|
||||
return some ⟨bvExpr, proof, expr⟩
|
||||
| _ =>
|
||||
/-
|
||||
Idea: we have t : Bool here, let's construct:
|
||||
BitVec.ofBool t : BitVec 1
|
||||
as an atom. Then construct the BVPred corresponding to
|
||||
BitVec.getLsb (BitVec.ofBool t) 0 : Bool
|
||||
We can prove that this is equivalent to `t`. This allows us to have boolean variables in BVPred.
|
||||
-/
|
||||
let ty ← inferType t
|
||||
let_expr Bool := ty | return none
|
||||
let atom ← ReifiedBVExpr.mkAtom (mkApp (mkConst ``BitVec.ofBool) t) 1
|
||||
let bvExpr : BVPred := .getLsbD atom.bvExpr 0
|
||||
let expr := mkApp3 (mkConst ``BVPred.getLsbD) (toExpr 1) atom.expr (toExpr 0)
|
||||
let proof := do
|
||||
let atomEval ← ReifiedBVExpr.mkEvalExpr atom.width atom.expr
|
||||
let atomProof ← atom.evalsAtAtoms
|
||||
return mkApp3
|
||||
(mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.ofBool_congr)
|
||||
t
|
||||
atomEval
|
||||
atomProof
|
||||
return some ⟨bvExpr, proof, expr⟩
|
||||
def boolAtom (t : Expr) : M (Option ReifiedBVPred) := do
|
||||
/-
|
||||
Idea: we have t : Bool here, let's construct:
|
||||
BitVec.ofBool t : BitVec 1
|
||||
as an atom. Then construct the BVPred corresponding to
|
||||
BitVec.getLsb (BitVec.ofBool t) 0 : Bool
|
||||
We can prove that this is equivalent to `t`. This allows us to have boolean variables in BVPred.
|
||||
-/
|
||||
let ty ← inferType t
|
||||
let_expr Bool := ty | return none
|
||||
let atom ← ReifiedBVExpr.mkAtom (mkApp (mkConst ``BitVec.ofBool) t) 1
|
||||
let bvExpr : BVPred := .getLsbD atom.bvExpr 0
|
||||
let expr := mkApp3 (mkConst ``BVPred.getLsbD) (toExpr 1) atom.expr (toExpr 0)
|
||||
let proof := do
|
||||
let atomEval ← ReifiedBVExpr.mkEvalExpr atom.width atom.expr
|
||||
let atomProof ← atom.evalsAtAtoms
|
||||
return mkApp3
|
||||
(mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.ofBool_congr)
|
||||
t
|
||||
atomEval
|
||||
atomProof
|
||||
return some ⟨bvExpr, proof, expr⟩
|
||||
|
||||
/--
|
||||
Reify an `Expr` that is a predicate about `BitVec`.
|
||||
Unless this function is called on something that is not a `Bool` it is always going to return `some`.
|
||||
-/
|
||||
partial def of (t : Expr) : M (Option ReifiedBVPred) := do
|
||||
match ← go t with
|
||||
| some pred => return some pred
|
||||
| none => boolAtom t
|
||||
where
|
||||
/--
|
||||
Reify `t`, returns `none` if the reification procedure failed.
|
||||
-/
|
||||
go (t : Expr) : M (Option ReifiedBVPred) := do
|
||||
match_expr t with
|
||||
| BEq.beq α _ lhsExpr rhsExpr =>
|
||||
let_expr BitVec _ := α | return none
|
||||
binaryReflection lhsExpr rhsExpr .eq ``Std.Tactic.BVDecide.Reflect.BitVec.beq_congr
|
||||
| BitVec.ult _ lhsExpr rhsExpr =>
|
||||
binaryReflection lhsExpr rhsExpr .ult ``Std.Tactic.BVDecide.Reflect.BitVec.ult_congr
|
||||
| BitVec.getLsbD _ subExpr idxExpr =>
|
||||
let some sub ← ReifiedBVExpr.of subExpr | return none
|
||||
let some idx ← getNatValue? idxExpr | return none
|
||||
let bvExpr : BVPred := .getLsbD sub.bvExpr idx
|
||||
let expr := mkApp3 (mkConst ``BVPred.getLsbD) (toExpr sub.width) sub.expr idxExpr
|
||||
let proof := do
|
||||
let subEval ← ReifiedBVExpr.mkEvalExpr sub.width sub.expr
|
||||
let subProof ← sub.evalsAtAtoms
|
||||
return mkApp5
|
||||
(mkConst ``Std.Tactic.BVDecide.Reflect.BitVec.getLsbD_congr)
|
||||
idxExpr
|
||||
(toExpr sub.width)
|
||||
subExpr
|
||||
subEval
|
||||
subProof
|
||||
return some ⟨bvExpr, proof, expr⟩
|
||||
| _ => return none
|
||||
|
||||
binaryReflection (lhsExpr rhsExpr : Expr) (pred : BVBinPred) (congrThm : Name) :
|
||||
M (Option ReifiedBVPred) := do
|
||||
let some lhs ← ReifiedBVExpr.of lhsExpr | return none
|
||||
|
||||
@@ -520,7 +520,7 @@ where
|
||||
|
||||
@[builtin_tactic «case», builtin_incremental]
|
||||
def evalCase : Tactic
|
||||
| stx@`(tactic| case $[$tag $hs*]|* =>%$arr $tac:tacticSeq1Indented) =>
|
||||
| stx@`(tactic| case%$caseTk $[$tag $hs*]|* =>%$arr $tac:tacticSeq1Indented) =>
|
||||
-- disable incrementality if body is run multiple times
|
||||
Term.withoutTacticIncrementality (tag.size > 1) do
|
||||
for tag in tag, hs in hs do
|
||||
@@ -528,20 +528,20 @@ def evalCase : Tactic
|
||||
let g ← renameInaccessibles g hs
|
||||
setGoals [g]
|
||||
g.setTag Name.anonymous
|
||||
withCaseRef arr tac <| closeUsingOrAdmit <| withTacticInfoContext stx <|
|
||||
withCaseRef arr tac <| closeUsingOrAdmit <| withTacticInfoContext (mkNullNode #[caseTk, arr]) <|
|
||||
Term.withNarrowedArgTacticReuse (argIdx := 3) (evalTactic ·) stx
|
||||
setGoals gs
|
||||
| _ => throwUnsupportedSyntax
|
||||
|
||||
@[builtin_tactic «case'»] def evalCase' : Tactic
|
||||
| `(tactic| case' $[$tag $hs*]|* =>%$arr $tac:tacticSeq) => do
|
||||
| `(tactic| case'%$caseTk $[$tag $hs*]|* =>%$arr $tac:tacticSeq) => do
|
||||
let mut acc := #[]
|
||||
for tag in tag, hs in hs do
|
||||
let (g, gs) ← getCaseGoals tag
|
||||
let g ← renameInaccessibles g hs
|
||||
let mvarTag ← g.getTag
|
||||
setGoals [g]
|
||||
withCaseRef arr tac (evalTactic tac)
|
||||
withCaseRef arr tac <| withTacticInfoContext (mkNullNode #[caseTk, arr]) <| evalTactic tac
|
||||
let gs' ← getUnsolvedGoals
|
||||
if let [g'] := gs' then
|
||||
g'.setTag mvarTag
|
||||
|
||||
@@ -123,9 +123,7 @@ def realizeExtTheorem (structName : Name) (flat : Bool) : Elab.Command.CommandEl
|
||||
levelParams := info.levelParams
|
||||
}
|
||||
modifyEnv fun env => addProtected env extName
|
||||
Lean.addDeclarationRanges extName {
|
||||
range := ← getDeclarationRange (← getRef)
|
||||
selectionRange := ← getDeclarationRange (← getRef) }
|
||||
addAuxDeclarationRanges extName (← getRef) (← getRef)
|
||||
catch e =>
|
||||
throwError m!"\
|
||||
Failed to generate an 'ext' theorem for '{MessageData.ofConstName structName}': {e.toMessageData}"
|
||||
@@ -163,9 +161,7 @@ def realizeExtIffTheorem (extName : Name) : Elab.Command.CommandElabM Name := do
|
||||
-- Only declarations in a namespace can be protected:
|
||||
unless extIffName.isAtomic do
|
||||
modifyEnv fun env => addProtected env extIffName
|
||||
Lean.addDeclarationRanges extIffName {
|
||||
range := ← getDeclarationRange (← getRef)
|
||||
selectionRange := ← getDeclarationRange (← getRef) }
|
||||
addAuxDeclarationRanges extName (← getRef) (← getRef)
|
||||
catch e =>
|
||||
throwError m!"\
|
||||
Failed to generate an 'ext_iff' theorem from '{MessageData.ofConstName extName}': {e.toMessageData}\n\
|
||||
|
||||
@@ -27,8 +27,10 @@ open Meta
|
||||
syntax inductionAlt := ppDedent(ppLine) inductionAltLHS+ " => " (hole <|> syntheticHole <|> tacticSeq)
|
||||
```
|
||||
-/
|
||||
private def getAltLhses (alt : Syntax) : Syntax :=
|
||||
alt[0]
|
||||
private def getFirstAltLhs (alt : Syntax) : Syntax :=
|
||||
alt[0][0]
|
||||
(getAltLhses alt)[0]
|
||||
/-- Return `inductionAlt` name. It assumes `alt` does not have multiple `inductionAltLHS` -/
|
||||
private def getAltName (alt : Syntax) : Name :=
|
||||
let lhs := getFirstAltLhs alt
|
||||
@@ -70,7 +72,9 @@ def evalAlt (mvarId : MVarId) (alt : Syntax) (addInfo : TermElabM Unit) : Tactic
|
||||
let goals ← getGoals
|
||||
try
|
||||
setGoals [mvarId]
|
||||
closeUsingOrAdmit (withTacticInfoContext alt (addInfo *> evalTactic rhs))
|
||||
closeUsingOrAdmit <|
|
||||
withTacticInfoContext (mkNullNode #[getAltLhses alt, getAltDArrow alt]) <|
|
||||
(addInfo *> evalTactic rhs)
|
||||
finally
|
||||
setGoals goals
|
||||
|
||||
|
||||
@@ -914,7 +914,9 @@ private def applyAttributesCore
|
||||
Remark: if the declaration has syntax errors, `declName` may be `.anonymous` see issue #4309
|
||||
In this case, we skip attribute application.
|
||||
-/
|
||||
unless declName == .anonymous do
|
||||
if declName == .anonymous then
|
||||
return
|
||||
withDeclName declName do
|
||||
for attr in attrs do
|
||||
withRef attr.stx do withLogging do
|
||||
let env ← getEnv
|
||||
|
||||
@@ -243,11 +243,16 @@ instance : ToSnapshotTree SnapshotLeaf where
|
||||
structure DynamicSnapshot where
|
||||
/-- Concrete snapshot value as `Dynamic`. -/
|
||||
val : Dynamic
|
||||
/-- Snapshot tree retrieved from `val` before erasure. -/
|
||||
tree : SnapshotTree
|
||||
/--
|
||||
Snapshot tree retrieved from `val` before erasure. We do thunk even the first level as accessing
|
||||
it too early can create some unnecessary tasks from `toSnapshotTree` that are otherwise avoided by
|
||||
`(sync := true)` when accessing only after elaboration has finished. Early access can even lead to
|
||||
deadlocks when later forcing these unnecessary tasks on a starved thread pool.
|
||||
-/
|
||||
tree : Thunk SnapshotTree
|
||||
|
||||
instance : ToSnapshotTree DynamicSnapshot where
|
||||
toSnapshotTree s := s.tree
|
||||
toSnapshotTree s := s.tree.get
|
||||
|
||||
/-- Creates a `DynamicSnapshot` from a typed snapshot value. -/
|
||||
def DynamicSnapshot.ofTyped [TypeName α] [ToSnapshotTree α] (val : α) : DynamicSnapshot where
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/-
|
||||
Copyright (c) 2021 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Lean.MonadEnv
|
||||
|
||||
namespace Lean
|
||||
|
||||
structure LazyInitExtension (m : Type → Type) (α : Type) where
|
||||
ext : EnvExtension (Option α)
|
||||
fn : m α
|
||||
|
||||
instance [Monad m] [Inhabited α] : Inhabited (LazyInitExtension m α) where
|
||||
default := {
|
||||
ext := default
|
||||
fn := pure default
|
||||
}
|
||||
|
||||
/--
|
||||
Register an environment extension for storing the result of `fn`.
|
||||
We initialize the extension with `none`, and `fn` is executed the
|
||||
first time `LazyInit.get` is executed.
|
||||
|
||||
This kind of extension is useful for avoiding work duplication in
|
||||
scenarios where a thunk cannot be used because the computation depends
|
||||
on state from the `m` monad. For example, we may want to "cache" a collection
|
||||
of theorems as a `SimpLemmas` object. -/
|
||||
def registerLazyInitExtension (fn : m α) : IO (LazyInitExtension m α) := do
|
||||
let ext ← registerEnvExtension (pure none)
|
||||
return { ext, fn }
|
||||
|
||||
def LazyInitExtension.get [MonadEnv m] [Monad m] (init : LazyInitExtension m α) : m α := do
|
||||
match init.ext.getState (← getEnv) with
|
||||
| some a => return a
|
||||
| none =>
|
||||
let a ← init.fn
|
||||
modifyEnv fun env => init.ext.setState env (some a)
|
||||
return a
|
||||
|
||||
end Lean
|
||||
@@ -37,7 +37,7 @@ def constructorNameAsVariable : Linter where
|
||||
let warnings : IO.Ref (Std.HashMap String.Range (Syntax × Name × Name)) ← IO.mkRef {}
|
||||
|
||||
for tree in infoTrees do
|
||||
tree.visitM' (preNode := fun ci info _ => do
|
||||
tree.visitM' (postNode := fun ci info _ => do
|
||||
match info with
|
||||
| .ofTermInfo ti =>
|
||||
match ti.expr with
|
||||
|
||||
@@ -10,41 +10,55 @@ set_option linter.missingDocs true -- keep it documented
|
||||
|
||||
/-! # Unused variable Linter
|
||||
|
||||
This file implements the unused variable linter, which runs automatically on all commands
|
||||
and reports any local variables that are never referred to, using information from the info tree.
|
||||
This file implements the unused variable linter, which runs automatically on all
|
||||
commands and reports any local variables that are never referred to, using
|
||||
information from the info tree.
|
||||
|
||||
It is not immediately obvious but this is a surprisingly expensive check without some optimizations.
|
||||
The main complication is that it can be difficult to determine what constitutes a "use".
|
||||
For example, we would like this to be considered a use of `x`:
|
||||
It is not immediately obvious but this is a surprisingly expensive check without
|
||||
some optimizations. The main complication is that it can be difficult to
|
||||
determine what constitutes a "use" apart from direct references to a variable
|
||||
that we can easily find in the info tree. For example, we would like this to be
|
||||
considered a use of `x`:
|
||||
```
|
||||
def foo (x : Nat) : Nat := by assumption
|
||||
```
|
||||
|
||||
The final proof term is `fun x => x` so clearly `x` was used, but we can't make use of this because
|
||||
the final proof term is after we have abstracted over the original `fvar` for `x`. If we look
|
||||
further into the tactic state we can see the `fvar` show up in the instantiation to the original
|
||||
goal metavariable `?m : Nat := x`, but it is not always the case that we can follow metavariable
|
||||
instantiations to determine what happened after the fact, because tactics might skip the goal
|
||||
metavariable and instantiate some other metavariable created prior to it instead.
|
||||
The final proof term is `fun x => x` so clearly `x` was used, but we can't make
|
||||
use of this because the final proof term is after we have abstracted over the
|
||||
original `fvar` for `x`. Instead, we make sure to store the proof term before
|
||||
abstraction but after instantiation of mvars in the info tree and retrieve it in
|
||||
the linter. Using the instantiated term is very important as redoing that step
|
||||
in the linter can be prohibitively expensive. The downside of special-casing the
|
||||
definition body in this way is that while it works for parameters, it does not
|
||||
work for local variables in the body, so we ignore them by default if any tactic
|
||||
infos are present (`linter.unusedVariables.analyzeTactics`).
|
||||
|
||||
Instead, we use a (much more expensive) overapproximation, which is just to look through the entire
|
||||
metavariable context looking for occurrences of `x`. We use caching to ensure that this is still
|
||||
linear in the size of the info tree, even though there are many metavariable contexts in all the
|
||||
intermediate stages of elaboration; these are highly similar and make use of `PersistentHashMap`
|
||||
so there is a lot of subterm sharing we can take advantage of.
|
||||
If we do turn on this option and look further into the tactic state, we can see
|
||||
the `fvar` show up in the instantiation to the original goal metavariable
|
||||
`?m : Nat := x`, but it is not always the case that we can follow metavariable
|
||||
instantiations to determine what happened after the fact, because tactics might
|
||||
skip the goal metavariable and instantiate some other metavariable created prior
|
||||
to it instead. Instead, we use a (much more expensive) overapproximation, which
|
||||
is just to look through the entire metavariable context looking for occurrences
|
||||
of `x`. We use caching to ensure that this is still linear in the size of the
|
||||
info tree, even though there are many metavariable contexts in all the
|
||||
intermediate stages of elaboration; these are highly similar and make use of
|
||||
`PersistentHashMap` so there is a lot of subterm sharing we can take advantage
|
||||
of.
|
||||
|
||||
## The `@[unused_variables_ignore_fn]` attribute
|
||||
|
||||
Some occurrences of variables are deliberately unused, or at least we don't want to lint on unused
|
||||
variables in these positions. For example:
|
||||
Some occurrences of variables are deliberately unused, or at least we don't want
|
||||
to lint on unused variables in these positions. For example:
|
||||
|
||||
```
|
||||
def foo (x : Nat) : (y : Nat) → Nat := fun _ => x
|
||||
-- ^ don't lint this unused variable because it is public API
|
||||
```
|
||||
|
||||
They are generally a syntactic criterion, so we allow adding custom `IgnoreFunction`s so that
|
||||
external syntax can also opt in to lint suppression, like so:
|
||||
They are generally a syntactic criterion, so we allow adding custom
|
||||
`IgnoreFunction`s so that external syntax can also opt in to lint suppression,
|
||||
like so:
|
||||
|
||||
```
|
||||
macro (name := foobarKind) "foobar " name:ident : command => `(def foo ($name : Nat) := 0)
|
||||
@@ -77,6 +91,17 @@ register_builtin_option linter.unusedVariables.patternVars : Bool := {
|
||||
defValue := true,
|
||||
descr := "enable the 'unused variables' linter to mark unused pattern variables"
|
||||
}
|
||||
/-- Enables linting variables defined in tactic blocks, may be expensive for complex proofs -/
|
||||
register_builtin_option linter.unusedVariables.analyzeTactics : Bool := {
|
||||
defValue := false
|
||||
descr := "enable analysis of local variables in presence of tactic proofs\
|
||||
\n\
|
||||
\nBy default, the linter will limit itself to linting a declaration's parameters \
|
||||
whenever tactic proofs are present as these can be expensive to analyze. Enabling this \
|
||||
option extends linting to local variables both inside and outside tactic proofs, \
|
||||
though it can also lead to some false negatives as intermediate tactic states may \
|
||||
reference some variables without the declaration ultimately depending on them."
|
||||
}
|
||||
|
||||
/-- Gets the status of `linter.unusedVariables` -/
|
||||
def getLinterUnusedVariables (o : Options) : Bool :=
|
||||
@@ -356,55 +381,82 @@ structure References where
|
||||
|
||||
/-- Collect information from the `infoTrees` into `References`.
|
||||
See `References` for more information about the return value. -/
|
||||
def collectReferences (infoTrees : Array Elab.InfoTree) (cmdStxRange : String.Range) :
|
||||
StateRefT References IO Unit := do
|
||||
for tree in infoTrees do
|
||||
tree.visitM' (preNode := fun ci info _ => do
|
||||
match info with
|
||||
| .ofTermInfo ti =>
|
||||
match ti.expr with
|
||||
| .const .. =>
|
||||
if ti.isBinder then
|
||||
let some range := info.range? | return
|
||||
let .original .. := info.stx.getHeadInfo | return -- we are not interested in canonical syntax here
|
||||
modify fun s => { s with constDecls := s.constDecls.insert range }
|
||||
| .fvar id .. =>
|
||||
let some range := info.range? | return
|
||||
let .original .. := info.stx.getHeadInfo | return -- we are not interested in canonical syntax here
|
||||
if ti.isBinder then
|
||||
-- This is a local variable declaration.
|
||||
let some ldecl := ti.lctx.find? id | return
|
||||
-- Skip declarations which are outside the command syntax range, like `variable`s
|
||||
-- (it would be confusing to lint these), or those which are macro-generated
|
||||
if !cmdStxRange.contains range.start || ldecl.userName.hasMacroScopes then return
|
||||
let opts := ci.options
|
||||
-- we have to check for the option again here because it can be set locally
|
||||
if !getLinterUnusedVariables opts then return
|
||||
let stx := skipDeclIdIfPresent info.stx
|
||||
if let .str _ s := stx.getId then
|
||||
-- If the variable name is `_foo` then it is intentionally (possibly) unused, so skip.
|
||||
-- This is the suggested way to silence the warning
|
||||
if s.startsWith "_" then return
|
||||
-- Record this either as a new `fvarDefs`, or an alias of an existing one
|
||||
modify fun s =>
|
||||
if let some ref := s.fvarDefs[range]? then
|
||||
{ s with fvarDefs := s.fvarDefs.insert range { ref with aliases := ref.aliases.push id } }
|
||||
else
|
||||
{ s with fvarDefs := s.fvarDefs.insert range { userName := ldecl.userName, stx, opts, aliases := #[id] } }
|
||||
else
|
||||
-- Found a direct use, keep track of it
|
||||
modify fun s => { s with fvarUses := s.fvarUses.insert id }
|
||||
| _ => pure ()
|
||||
| .ofTacticInfo ti =>
|
||||
-- Keep track of the `MetavarContext` after a tactic for later
|
||||
modify fun s => { s with assignments := s.assignments.push ti.mctxAfter.eAssignment }
|
||||
| .ofFVarAliasInfo i =>
|
||||
-- record any aliases we find
|
||||
modify fun s =>
|
||||
let id := followAliases s.fvarAliases i.baseId
|
||||
{ s with fvarAliases := s.fvarAliases.insert i.id id }
|
||||
| _ => pure ())
|
||||
partial def collectReferences (infoTrees : Array Elab.InfoTree) (cmdStxRange : String.Range) :
|
||||
StateRefT References IO Unit := ReaderT.run (r := false) <| go infoTrees none
|
||||
where
|
||||
go infoTrees ctx? := do
|
||||
for tree in infoTrees do
|
||||
tree.visitM' (ctx? := ctx?) (preNode := fun ci info children => do
|
||||
-- set if `analyzeTactics` is unset, tactic infos are present, and we're inside the body
|
||||
let ignored ← read
|
||||
match info with
|
||||
| .ofTermInfo ti =>
|
||||
-- NOTE: we have to do this check *before* `ignored` because nested bodies (e.g. from
|
||||
-- nested `let rec`s) do need to be included to find all `Expr` uses of the top-level
|
||||
-- parameters
|
||||
if ti.elaborator == `MutualDef.body &&
|
||||
!linter.unusedVariables.analyzeTactics.get ci.options then
|
||||
-- the body is the only `Expr` we will analyze in this case
|
||||
-- NOTE: we include it even if no tactics are present as at least for parameters we want
|
||||
-- to lint only truly unused binders
|
||||
let (e, _) := instantiateMVarsCore ci.mctx ti.expr
|
||||
modify fun s => { s with
|
||||
assignments := s.assignments.push (.insert {} ⟨.anonymous⟩ e) }
|
||||
let tacticsPresent := children.any (·.findInfo? (· matches .ofTacticInfo ..) |>.isSome)
|
||||
withReader (· || tacticsPresent) do
|
||||
go children.toArray ci
|
||||
return false
|
||||
if ignored then return true
|
||||
match ti.expr with
|
||||
| .const .. =>
|
||||
if ti.isBinder then
|
||||
let some range := info.range? | return true
|
||||
let .original .. := info.stx.getHeadInfo | return true -- we are not interested in canonical syntax here
|
||||
modify fun s => { s with constDecls := s.constDecls.insert range }
|
||||
| .fvar id .. =>
|
||||
let some range := info.range? | return true
|
||||
let .original .. := info.stx.getHeadInfo | return true -- we are not interested in canonical syntax here
|
||||
if ti.isBinder then
|
||||
-- This is a local variable declaration.
|
||||
if ignored then return true
|
||||
let some ldecl := ti.lctx.find? id | return true
|
||||
-- Skip declarations which are outside the command syntax range, like `variable`s
|
||||
-- (it would be confusing to lint these), or those which are macro-generated
|
||||
if !cmdStxRange.contains range.start || ldecl.userName.hasMacroScopes then return true
|
||||
let opts := ci.options
|
||||
-- we have to check for the option again here because it can be set locally
|
||||
if !getLinterUnusedVariables opts then return true
|
||||
let stx := skipDeclIdIfPresent info.stx
|
||||
if let .str _ s := stx.getId then
|
||||
-- If the variable name is `_foo` then it is intentionally (possibly) unused, so skip.
|
||||
-- This is the suggested way to silence the warning
|
||||
if s.startsWith "_" then return true
|
||||
-- Record this either as a new `fvarDefs`, or an alias of an existing one
|
||||
modify fun s =>
|
||||
if let some ref := s.fvarDefs[range]? then
|
||||
{ s with fvarDefs := s.fvarDefs.insert range { ref with aliases := ref.aliases.push id } }
|
||||
else
|
||||
{ s with fvarDefs := s.fvarDefs.insert range { userName := ldecl.userName, stx, opts, aliases := #[id] } }
|
||||
else
|
||||
-- Found a direct use, keep track of it
|
||||
modify fun s => { s with fvarUses := s.fvarUses.insert id }
|
||||
| _ => pure ()
|
||||
return true
|
||||
| .ofTacticInfo ti =>
|
||||
-- When ignoring new binders, no need to look at intermediate tactic states either as
|
||||
-- references to binders outside the body will be covered by the body `Expr`
|
||||
if ignored then return true
|
||||
-- Keep track of the `MetavarContext` after a tactic for later
|
||||
modify fun s => { s with assignments := s.assignments.push ti.mctxAfter.eAssignment }
|
||||
return true
|
||||
| .ofFVarAliasInfo i =>
|
||||
if ignored then return true
|
||||
-- record any aliases we find
|
||||
modify fun s =>
|
||||
let id := followAliases s.fvarAliases i.baseId
|
||||
{ s with fvarAliases := s.fvarAliases.insert i.id id }
|
||||
return true
|
||||
| _ => return true)
|
||||
/-- Since declarations attach the declaration info to the `declId`,
|
||||
we skip that to get to the `.ident` if possible. -/
|
||||
skipDeclIdIfPresent (stx : Syntax) : Syntax :=
|
||||
@@ -493,7 +545,7 @@ def unusedVariables : Linter where
|
||||
-- collect additional `fvarUses` from tactic assignments
|
||||
visitAssignments (← IO.mkRef {}) fvarUsesRef s.assignments
|
||||
-- Resolve potential aliases again to preserve `fvarUsesRef` invariant
|
||||
fvarUsesRef.modify fun fvarUses => fvarUses.fold (·.insert <| getCanonVar ·) {}
|
||||
fvarUsesRef.modify fun fvarUses => fvarUses.toArray.map getCanonVar |> .insertMany {}
|
||||
initializedMVars := true
|
||||
let fvarUses ← fvarUsesRef.get
|
||||
-- Redo the initial check because `fvarUses` could be bigger now
|
||||
|
||||
@@ -441,6 +441,8 @@ This can be used to infer the expected type of the alternatives when constructin
|
||||
-/
|
||||
def arrowDomainsN (n : Nat) (type : Expr) : MetaM (Array Expr) := do
|
||||
forallBoundedTelescope type n fun xs _ => do
|
||||
unless xs.size = n do
|
||||
throwError "type {type} does not have {n} parameters"
|
||||
let types ← xs.mapM (inferType ·)
|
||||
for t in types do
|
||||
if t.hasAnyFVar (fun fvar => xs.contains (.fvar fvar)) then
|
||||
|
||||
@@ -4,31 +4,26 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Leonardo de Moura
|
||||
-/
|
||||
prelude
|
||||
import Lean.LazyInitExtension
|
||||
import Lean.Meta.Tactic.Cases
|
||||
import Lean.Meta.Tactic.Simp.Main
|
||||
|
||||
namespace Lean.Meta
|
||||
namespace SplitIf
|
||||
|
||||
builtin_initialize ext : LazyInitExtension MetaM Simp.Context ←
|
||||
registerLazyInitExtension do
|
||||
let mut s : SimpTheorems := {}
|
||||
s ← s.addConst ``if_pos
|
||||
s ← s.addConst ``if_neg
|
||||
s ← s.addConst ``dif_pos
|
||||
s ← s.addConst ``dif_neg
|
||||
return {
|
||||
simpTheorems := #[s]
|
||||
congrTheorems := (← getSimpCongrTheorems)
|
||||
config := { Simp.neutralConfig with dsimp := false }
|
||||
}
|
||||
|
||||
/--
|
||||
Default `Simp.Context` for `simpIf` methods. It contains all congruence theorems, but
|
||||
just the rewriting rules for reducing `if` expressions. -/
|
||||
def getSimpContext : MetaM Simp.Context :=
|
||||
ext.get
|
||||
def getSimpContext : MetaM Simp.Context := do
|
||||
let mut s : SimpTheorems := {}
|
||||
s ← s.addConst ``if_pos
|
||||
s ← s.addConst ``if_neg
|
||||
s ← s.addConst ``dif_pos
|
||||
s ← s.addConst ``dif_neg
|
||||
return {
|
||||
simpTheorems := #[s]
|
||||
congrTheorems := (← getSimpCongrTheorems)
|
||||
config := { Simp.neutralConfig with dsimp := false }
|
||||
}
|
||||
|
||||
/--
|
||||
Default `discharge?` function for `simpIf` methods.
|
||||
|
||||
@@ -505,6 +505,9 @@ Displays all available tactic tags, with documentation.
|
||||
-/
|
||||
@[builtin_command_parser] def printTacTags := leading_parser
|
||||
"#print " >> nonReservedSymbol "tactic " >> nonReservedSymbol "tags"
|
||||
/-- Shows the current Lean version. Prints `Lean.versionString`. -/
|
||||
@[builtin_command_parser] def version := leading_parser
|
||||
"#version"
|
||||
@[builtin_command_parser] def «init_quot» := leading_parser
|
||||
"init_quot"
|
||||
def optionValue := nonReservedSymbol "true" <|> nonReservedSymbol "false" <|> strLit <|> numLit
|
||||
|
||||
@@ -1215,32 +1215,11 @@ def delabDo : Delab := whenPPOption getPPNotation do
|
||||
let items ← elems.toArray.mapM (`(doSeqItem|$(·):doElem))
|
||||
`(do $items:doSeqItem*)
|
||||
|
||||
def reifyName : Expr → DelabM Name
|
||||
| .const ``Lean.Name.anonymous _ => return Name.anonymous
|
||||
| mkApp2 (.const ``Lean.Name.str _) n (.lit (.strVal s)) => return (← reifyName n).mkStr s
|
||||
| mkApp2 (.const ``Lean.Name.num _) n (.lit (.natVal i)) => return (← reifyName n).mkNum i
|
||||
| mkApp (.const ``Lean.Name.mkStr1 _) (.lit (.strVal a)) => return Lean.Name.mkStr1 a
|
||||
| mkApp2 (.const ``Lean.Name.mkStr2 _) (.lit (.strVal a1)) (.lit (.strVal a2)) =>
|
||||
return Lean.Name.mkStr2 a1 a2
|
||||
| mkApp3 (.const ``Lean.Name.mkStr3 _) (.lit (.strVal a1)) (.lit (.strVal a2)) (.lit (.strVal a3)) =>
|
||||
return Lean.Name.mkStr3 a1 a2 a3
|
||||
| mkApp4 (.const ``Lean.Name.mkStr4 _) (.lit (.strVal a1)) (.lit (.strVal a2)) (.lit (.strVal a3)) (.lit (.strVal a4)) =>
|
||||
return Lean.Name.mkStr4 a1 a2 a3 a4
|
||||
| mkApp5 (.const ``Lean.Name.mkStr5 _) (.lit (.strVal a1)) (.lit (.strVal a2)) (.lit (.strVal a3)) (.lit (.strVal a4)) (.lit (.strVal a5)) =>
|
||||
return Lean.Name.mkStr5 a1 a2 a3 a4 a5
|
||||
| mkApp6 (.const ``Lean.Name.mkStr6 _) (.lit (.strVal a1)) (.lit (.strVal a2)) (.lit (.strVal a3)) (.lit (.strVal a4)) (.lit (.strVal a5)) (.lit (.strVal a6)) =>
|
||||
return Lean.Name.mkStr6 a1 a2 a3 a4 a5 a6
|
||||
| mkApp7 (.const ``Lean.Name.mkStr7 _) (.lit (.strVal a1)) (.lit (.strVal a2)) (.lit (.strVal a3)) (.lit (.strVal a4)) (.lit (.strVal a5)) (.lit (.strVal a6)) (.lit (.strVal a7)) =>
|
||||
return Lean.Name.mkStr7 a1 a2 a3 a4 a5 a6 a7
|
||||
| mkApp8 (.const ``Lean.Name.mkStr8 _) (.lit (.strVal a1)) (.lit (.strVal a2)) (.lit (.strVal a3)) (.lit (.strVal a4)) (.lit (.strVal a5)) (.lit (.strVal a6)) (.lit (.strVal a7)) (.lit (.strVal a8)) =>
|
||||
return Lean.Name.mkStr8 a1 a2 a3 a4 a5 a6 a7 a8
|
||||
| _ => failure
|
||||
|
||||
@[builtin_delab app.Lean.Name.str,
|
||||
builtin_delab app.Lean.Name.mkStr1, builtin_delab app.Lean.Name.mkStr2, builtin_delab app.Lean.Name.mkStr3, builtin_delab app.Lean.Name.mkStr4,
|
||||
builtin_delab app.Lean.Name.mkStr5, builtin_delab app.Lean.Name.mkStr6, builtin_delab app.Lean.Name.mkStr7, builtin_delab app.Lean.Name.mkStr8]
|
||||
def delabNameMkStr : Delab := whenPPOption getPPNotation do
|
||||
let n ← reifyName (← getExpr)
|
||||
let some n := (← getExpr).name? | failure
|
||||
-- not guaranteed to be a syntactically valid name, but usually more helpful than the explicit version
|
||||
return mkNode ``Lean.Parser.Term.quotedName #[Syntax.mkNameLit s!"`{n}"]
|
||||
|
||||
|
||||
@@ -40,27 +40,34 @@ structure InfoWithCtx where
|
||||
info : Elab.Info
|
||||
children : PersistentArray InfoTree
|
||||
|
||||
/-- Visit nodes, passing in a surrounding context (the innermost one combined with all outer ones)
|
||||
and accumulating results on the way back up. -/
|
||||
/--
|
||||
Visit nodes, passing in a surrounding context (the innermost one combined with all outer ones) and
|
||||
accumulating results on the way back up. If `preNode` returns `false`, the children of the current
|
||||
node are skipped and `postNode` is invoked with an empty list of results.
|
||||
-/
|
||||
partial def InfoTree.visitM [Monad m]
|
||||
(preNode : ContextInfo → Info → (children : PersistentArray InfoTree) → m Unit := fun _ _ _ => pure ())
|
||||
(preNode : ContextInfo → Info → (children : PersistentArray InfoTree) → m Bool := fun _ _ _ => pure true)
|
||||
(postNode : ContextInfo → Info → (children : PersistentArray InfoTree) → List (Option α) → m α)
|
||||
: InfoTree → m (Option α) :=
|
||||
go none
|
||||
(ctx? : Option ContextInfo := none) : InfoTree → m (Option α) :=
|
||||
go ctx?
|
||||
where go
|
||||
| ctx?, context ctx t => go (ctx.mergeIntoOuter? ctx?) t
|
||||
| some ctx, node i cs => do
|
||||
preNode ctx i cs
|
||||
let as ← cs.toList.mapM (go <| i.updateContext? ctx)
|
||||
postNode ctx i cs as
|
||||
let visitChildren ← preNode ctx i cs
|
||||
if !visitChildren then
|
||||
postNode ctx i cs []
|
||||
else
|
||||
let as ← cs.toList.mapM (go <| i.updateContext? ctx)
|
||||
postNode ctx i cs as
|
||||
| none, node .. => panic! "unexpected context-free info tree node"
|
||||
| _, hole .. => pure none
|
||||
|
||||
/-- `InfoTree.visitM` specialized to `Unit` return type -/
|
||||
def InfoTree.visitM' [Monad m]
|
||||
(preNode : ContextInfo → Info → (children : PersistentArray InfoTree) → m Unit := fun _ _ _ => pure ())
|
||||
(preNode : ContextInfo → Info → (children : PersistentArray InfoTree) → m Bool := fun _ _ _ => pure true)
|
||||
(postNode : ContextInfo → Info → (children : PersistentArray InfoTree) → m Unit := fun _ _ _ => pure ())
|
||||
(t : InfoTree) : m Unit := t.visitM preNode (fun ci i cs _ => postNode ci i cs) |> discard
|
||||
(ctx? : Option ContextInfo := none) (t : InfoTree) : m Unit :=
|
||||
t.visitM preNode (fun ci i cs _ => postNode ci i cs) ctx? |> discard
|
||||
|
||||
/--
|
||||
Visit nodes bottom-up, passing in a surrounding context (the innermost one) and the union of nested results (empty at leaves). -/
|
||||
@@ -410,6 +417,9 @@ where go ci?
|
||||
match ci?, i with
|
||||
| some ci, .ofTermInfo ti
|
||||
| some ci, .ofOmissionInfo { toTermInfo := ti, .. } => do
|
||||
-- NOTE: `instantiateMVars` can potentially be expensive but we rely on the elaborator
|
||||
-- creating a fully instantiated `MutualDef.body` term info node which has the implicit effect
|
||||
-- of making the `instantiateMVars` here a no-op and avoids further recursing into the body
|
||||
let expr ← ti.runMetaM ci (instantiateMVars ti.expr)
|
||||
return expr.hasSorry
|
||||
-- we assume that `cs` are subterms of `ti.expr` and
|
||||
|
||||
@@ -106,4 +106,29 @@ def arrayLit? (e : Expr) : Option (Expr × List Expr) :=
|
||||
def prod? (e : Expr) : Option (Expr × Expr) :=
|
||||
e.app2? ``Prod
|
||||
|
||||
/--
|
||||
Checks if an expression is a `Name` literal, and if so returns the name.
|
||||
-/
|
||||
def name? : Expr → Option Name
|
||||
| .const ``Lean.Name.anonymous _ => Name.anonymous
|
||||
| mkApp2 (.const ``Lean.Name.str _) n (.lit (.strVal s)) => (name? n).map (·.str s)
|
||||
| mkApp2 (.const ``Lean.Name.num _) n i =>
|
||||
(i.rawNatLit? <|> i.nat?).bind fun i => (name? n).map (Name.num · i)
|
||||
| mkApp (.const ``Lean.Name.mkStr1 _) (.lit (.strVal a)) => Lean.Name.mkStr1 a
|
||||
| mkApp2 (.const ``Lean.Name.mkStr2 _) (.lit (.strVal a1)) (.lit (.strVal a2)) =>
|
||||
Lean.Name.mkStr2 a1 a2
|
||||
| mkApp3 (.const ``Lean.Name.mkStr3 _) (.lit (.strVal a1)) (.lit (.strVal a2)) (.lit (.strVal a3)) =>
|
||||
Lean.Name.mkStr3 a1 a2 a3
|
||||
| mkApp4 (.const ``Lean.Name.mkStr4 _) (.lit (.strVal a1)) (.lit (.strVal a2)) (.lit (.strVal a3)) (.lit (.strVal a4)) =>
|
||||
Lean.Name.mkStr4 a1 a2 a3 a4
|
||||
| mkApp5 (.const ``Lean.Name.mkStr5 _) (.lit (.strVal a1)) (.lit (.strVal a2)) (.lit (.strVal a3)) (.lit (.strVal a4)) (.lit (.strVal a5)) =>
|
||||
Lean.Name.mkStr5 a1 a2 a3 a4 a5
|
||||
| mkApp6 (.const ``Lean.Name.mkStr6 _) (.lit (.strVal a1)) (.lit (.strVal a2)) (.lit (.strVal a3)) (.lit (.strVal a4)) (.lit (.strVal a5)) (.lit (.strVal a6)) =>
|
||||
Lean.Name.mkStr6 a1 a2 a3 a4 a5 a6
|
||||
| mkApp7 (.const ``Lean.Name.mkStr7 _) (.lit (.strVal a1)) (.lit (.strVal a2)) (.lit (.strVal a3)) (.lit (.strVal a4)) (.lit (.strVal a5)) (.lit (.strVal a6)) (.lit (.strVal a7)) =>
|
||||
Lean.Name.mkStr7 a1 a2 a3 a4 a5 a6 a7
|
||||
| mkApp8 (.const ``Lean.Name.mkStr8 _) (.lit (.strVal a1)) (.lit (.strVal a2)) (.lit (.strVal a3)) (.lit (.strVal a4)) (.lit (.strVal a5)) (.lit (.strVal a6)) (.lit (.strVal a7)) (.lit (.strVal a8)) =>
|
||||
Lean.Name.mkStr8 a1 a2 a3 a4 a5 a6 a7 a8
|
||||
| _ => none
|
||||
|
||||
end Lean.Expr
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.Basic
|
||||
import Std.Sat.AIG.LawfulOperator
|
||||
import Std.Sat.AIG.Lemmas
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Data.HashMap
|
||||
import Std.Data.HashSet
|
||||
|
||||
@@ -127,7 +128,7 @@ theorem Cache.get?_property {decls : Array (Decl α)} {idx : Nat} (c : Cache α
|
||||
induction hcache generalizing decl with
|
||||
| empty => simp at hfound
|
||||
| push_id wf ih =>
|
||||
rw [Array.get_push]
|
||||
rw [Array.getElem_push]
|
||||
split
|
||||
· apply ih
|
||||
simp [hfound]
|
||||
@@ -139,7 +140,7 @@ theorem Cache.get?_property {decls : Array (Decl α)} {idx : Nat} (c : Cache α
|
||||
assumption
|
||||
| push_cache wf ih =>
|
||||
rename_i decl'
|
||||
rw [Array.get_push]
|
||||
rw [Array.getElem_push]
|
||||
split
|
||||
· simp only [HashMap.getElem?_insert] at hfound
|
||||
match heq : decl == decl' with
|
||||
@@ -463,7 +464,7 @@ def mkGate (aig : AIG α) (input : GateInput aig) : Entrypoint α :=
|
||||
let cache := aig.cache.noUpdate
|
||||
have invariant := by
|
||||
intro i lhs' rhs' linv' rinv' h1 h2
|
||||
simp only [Array.get_push] at h2
|
||||
simp only [Array.getElem_push] at h2
|
||||
split at h2
|
||||
· apply aig.invariant <;> assumption
|
||||
· injections
|
||||
@@ -482,7 +483,7 @@ def mkAtom (aig : AIG α) (n : α) : Entrypoint α :=
|
||||
let cache := aig.cache.noUpdate
|
||||
have invariant := by
|
||||
intro i lhs rhs linv rinv h1 h2
|
||||
simp only [Array.get_push] at h2
|
||||
simp only [Array.getElem_push] at h2
|
||||
split at h2
|
||||
· apply aig.invariant <;> assumption
|
||||
· contradiction
|
||||
@@ -498,7 +499,7 @@ def mkConst (aig : AIG α) (val : Bool) : Entrypoint α :=
|
||||
let cache := aig.cache.noUpdate
|
||||
have invariant := by
|
||||
intro i lhs rhs linv rinv h1 h2
|
||||
simp only [Array.get_push] at h2
|
||||
simp only [Array.getElem_push] at h2
|
||||
split at h2
|
||||
· apply aig.invariant <;> assumption
|
||||
· contradiction
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.CNF
|
||||
import Std.Sat.AIG.Basic
|
||||
import Std.Sat.AIG.Lemmas
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.Basic
|
||||
import Std.Sat.AIG.Lemmas
|
||||
|
||||
@@ -35,7 +36,7 @@ def mkAtomCached (aig : AIG α) (n : α) : Entrypoint α :=
|
||||
let decls := decls.push decl
|
||||
have inv := by
|
||||
intro i lhs rhs linv rinv h1 h2
|
||||
simp only [Array.get_push] at h2
|
||||
simp only [Array.getElem_push] at h2
|
||||
split at h2
|
||||
· apply inv <;> assumption
|
||||
· contradiction
|
||||
@@ -57,7 +58,7 @@ def mkConstCached (aig : AIG α) (val : Bool) : Entrypoint α :=
|
||||
let decls := decls.push decl
|
||||
have inv := by
|
||||
intro i lhs rhs linv rinv h1 h2
|
||||
simp only [Array.get_push] at h2
|
||||
simp only [Array.getElem_push] at h2
|
||||
split at h2
|
||||
· apply inv <;> assumption
|
||||
· contradiction
|
||||
@@ -120,7 +121,7 @@ where
|
||||
have inv := by
|
||||
intro i lhs rhs linv rinv h1 h2
|
||||
simp only [decls] at *
|
||||
simp only [Array.get_push] at h2
|
||||
simp only [Array.getElem_push] at h2
|
||||
split at h2
|
||||
· apply inv <;> assumption
|
||||
· injections; omega
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.Cached
|
||||
import Std.Sat.AIG.CachedLemmas
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.CachedGates
|
||||
import Std.Sat.AIG.LawfulOperator
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.Cached
|
||||
|
||||
/-!
|
||||
@@ -59,7 +60,7 @@ theorem mkAtomCached_decl_eq (aig : AIG α) (var : α) (idx : Nat) {h : idx < ai
|
||||
simp [this]
|
||||
| none =>
|
||||
have := mkAtomCached_miss_aig aig hcache
|
||||
simp only [this, Array.get_push]
|
||||
simp only [this, Array.getElem_push]
|
||||
split
|
||||
· rfl
|
||||
· contradiction
|
||||
@@ -133,7 +134,7 @@ theorem mkConstCached_decl_eq (aig : AIG α) (val : Bool) (idx : Nat) {h : idx <
|
||||
simp [this]
|
||||
| none =>
|
||||
have := mkConstCached_miss_aig aig hcache
|
||||
simp only [this, Array.get_push]
|
||||
simp only [this, Array.getElem_push]
|
||||
split
|
||||
· rfl
|
||||
· contradiction
|
||||
@@ -256,7 +257,7 @@ theorem mkGateCached.go_decl_eq (aig : AIG α) (input : GateInput aig) :
|
||||
· rw [← hres]
|
||||
dsimp only
|
||||
intro idx h1 h2
|
||||
rw [Array.get_push]
|
||||
rw [Array.getElem_push]
|
||||
simp [h2]
|
||||
|
||||
/--
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.CachedGatesLemmas
|
||||
import Std.Sat.AIG.LawfulVecOperator
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.Basic
|
||||
|
||||
/-!
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.LawfulOperator
|
||||
import Std.Sat.AIG.RefVec
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.Basic
|
||||
import Std.Sat.AIG.LawfulOperator
|
||||
|
||||
@@ -77,7 +78,7 @@ The AIG produced by `AIG.mkGate` agrees with the input AIG on all indices that a
|
||||
theorem mkGate_decl_eq idx (aig : AIG α) (input : GateInput aig) {h : idx < aig.decls.size} :
|
||||
have := mkGate_le_size aig input
|
||||
(aig.mkGate input).aig.decls[idx]'(by omega) = aig.decls[idx] := by
|
||||
simp only [mkGate, Array.get_push]
|
||||
simp only [mkGate, Array.getElem_push]
|
||||
split
|
||||
· rfl
|
||||
· contradiction
|
||||
@@ -98,13 +99,13 @@ theorem denote_mkGate {aig : AIG α} {input : GateInput aig} :
|
||||
unfold denote denote.go
|
||||
split
|
||||
· next heq =>
|
||||
rw [mkGate, Array.get_push_eq] at heq
|
||||
rw [mkGate, Array.getElem_push_eq] at heq
|
||||
contradiction
|
||||
· next heq =>
|
||||
rw [mkGate, Array.get_push_eq] at heq
|
||||
rw [mkGate, Array.getElem_push_eq] at heq
|
||||
contradiction
|
||||
· next heq =>
|
||||
rw [mkGate, Array.get_push_eq] at heq
|
||||
rw [mkGate, Array.getElem_push_eq] at heq
|
||||
injection heq with heq1 heq2 heq3 heq4
|
||||
dsimp only
|
||||
congr 2
|
||||
@@ -131,7 +132,7 @@ The AIG produced by `AIG.mkAtom` agrees with the input AIG on all indices that a
|
||||
-/
|
||||
theorem mkAtom_decl_eq (aig : AIG α) (var : α) (idx : Nat) {h : idx < aig.decls.size} {hbound} :
|
||||
(aig.mkAtom var).aig.decls[idx]'hbound = aig.decls[idx] := by
|
||||
simp only [mkAtom, Array.get_push]
|
||||
simp only [mkAtom, Array.getElem_push]
|
||||
split
|
||||
· rfl
|
||||
· contradiction
|
||||
@@ -148,14 +149,14 @@ theorem denote_mkAtom {aig : AIG α} :
|
||||
unfold denote denote.go
|
||||
split
|
||||
· next heq =>
|
||||
rw [mkAtom, Array.get_push_eq] at heq
|
||||
rw [mkAtom, Array.getElem_push_eq] at heq
|
||||
contradiction
|
||||
· next heq =>
|
||||
rw [mkAtom, Array.get_push_eq] at heq
|
||||
rw [mkAtom, Array.getElem_push_eq] at heq
|
||||
injection heq with heq
|
||||
rw [heq]
|
||||
· next heq =>
|
||||
rw [mkAtom, Array.get_push_eq] at heq
|
||||
rw [mkAtom, Array.getElem_push_eq] at heq
|
||||
contradiction
|
||||
|
||||
/--
|
||||
@@ -171,7 +172,7 @@ The AIG produced by `AIG.mkConst` agrees with the input AIG on all indices that
|
||||
theorem mkConst_decl_eq (aig : AIG α) (val : Bool) (idx : Nat) {h : idx < aig.decls.size} :
|
||||
have := mkConst_le_size aig val
|
||||
(aig.mkConst val).aig.decls[idx]'(by omega) = aig.decls[idx] := by
|
||||
simp only [mkConst, Array.get_push]
|
||||
simp only [mkConst, Array.getElem_push]
|
||||
split
|
||||
· rfl
|
||||
· contradiction
|
||||
@@ -187,14 +188,14 @@ theorem denote_mkConst {aig : AIG α} : ⟦(aig.mkConst val), assign⟧ = val :=
|
||||
unfold denote denote.go
|
||||
split
|
||||
· next heq =>
|
||||
rw [mkConst, Array.get_push_eq] at heq
|
||||
rw [mkConst, Array.getElem_push_eq] at heq
|
||||
injection heq with heq
|
||||
rw [heq]
|
||||
· next heq =>
|
||||
rw [mkConst, Array.get_push_eq] at heq
|
||||
rw [mkConst, Array.getElem_push_eq] at heq
|
||||
contradiction
|
||||
· next heq =>
|
||||
rw [mkConst, Array.get_push_eq] at heq
|
||||
rw [mkConst, Array.getElem_push_eq] at heq
|
||||
contradiction
|
||||
|
||||
/--
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.LawfulOperator
|
||||
import Std.Sat.AIG.CachedGatesLemmas
|
||||
|
||||
@@ -58,7 +59,7 @@ def push (s : RefVec aig len) (ref : AIG.Ref aig) : RefVec aig (len + 1) :=
|
||||
by simp [hlen],
|
||||
by
|
||||
intro i hi
|
||||
simp only [Array.get_push]
|
||||
simp only [Array.getElem_push]
|
||||
split
|
||||
· apply hrefs
|
||||
omega
|
||||
@@ -84,7 +85,7 @@ theorem get_push_ref_lt (s : RefVec aig len) (ref : AIG.Ref aig) (idx : Nat)
|
||||
simp only [get, push, Ref.mk.injEq]
|
||||
cases ref
|
||||
simp only [Ref.mk.injEq]
|
||||
rw [Array.get_push_lt]
|
||||
rw [Array.getElem_push_lt]
|
||||
|
||||
@[simp]
|
||||
theorem get_cast {aig1 aig2 : AIG α} (s : RefVec aig1 len) (idx : Nat) (hidx : idx < len)
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.RefVecOperator.Map
|
||||
import Std.Sat.AIG.RefVecOperator.Zip
|
||||
import Std.Sat.AIG.RefVecOperator.Fold
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.RefVec
|
||||
import Std.Sat.AIG.LawfulVecOperator
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.RefVec
|
||||
import Std.Sat.AIG.LawfulVecOperator
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.RefVec
|
||||
import Std.Sat.AIG.LawfulVecOperator
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.Basic
|
||||
import Std.Sat.AIG.Lemmas
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Std.Sat.AIG.Relabel
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Henrik Böving
|
||||
-/
|
||||
prelude
|
||||
import Init.Data.AC
|
||||
import Std.Tactic.BVDecide.Bitblast.BVExpr.Circuit.Impl.Var
|
||||
import Std.Tactic.BVDecide.Bitblast.BVExpr.Circuit.Impl.Const
|
||||
import Std.Tactic.BVDecide.Bitblast.BVExpr.Circuit.Impl.Operations.Not
|
||||
|
||||
@@ -111,7 +111,7 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
⟨units.size, units_size_lt_updatedUnits_size⟩
|
||||
have i_gt_zero : i.1 > 0 := by rw [i_eq_l]; exact l.1.2.1
|
||||
refine ⟨mostRecentUnitIdx, l.2, i_gt_zero, ?_⟩
|
||||
simp only [insertUnit, h3, ite_false, Array.get_push_eq, i_eq_l, reduceCtorEq]
|
||||
simp only [insertUnit, h3, ite_false, Array.getElem_push_eq, i_eq_l, reduceCtorEq]
|
||||
constructor
|
||||
· rfl
|
||||
· constructor
|
||||
@@ -132,7 +132,7 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
· intro h
|
||||
simp only [← h, not_true, mostRecentUnitIdx] at hk
|
||||
exact hk rfl
|
||||
rw [Array.get_push_lt _ _ _ k_in_bounds]
|
||||
rw [Array.getElem_push_lt _ _ _ k_in_bounds]
|
||||
rw [i_eq_l] at h2
|
||||
exact h2 ⟨k.1, k_in_bounds⟩
|
||||
· next i_ne_l =>
|
||||
@@ -142,7 +142,7 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
constructor
|
||||
· exact h1
|
||||
· intro j
|
||||
rw [Array.get_push]
|
||||
rw [Array.getElem_push]
|
||||
by_cases h : j.val < Array.size units
|
||||
· simp only [h, dite_true]
|
||||
exact h2 ⟨j.1, h⟩
|
||||
@@ -189,9 +189,9 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
exact h5 (has_add _ true)
|
||||
| true, false =>
|
||||
refine ⟨⟨j.1, j_lt_updatedUnits_size⟩, mostRecentUnitIdx, i_gt_zero, ?_⟩
|
||||
simp only [insertUnit, h5, ite_false, Array.get_push_eq, ne_eq, reduceCtorEq]
|
||||
simp only [insertUnit, h5, ite_false, Array.getElem_push_eq, ne_eq, reduceCtorEq]
|
||||
constructor
|
||||
· rw [Array.get_push_lt units l j.1 j.2, h1]
|
||||
· rw [Array.getElem_push_lt units l j.1 j.2, h1]
|
||||
· constructor
|
||||
· simp [i_eq_l, ← hl]
|
||||
rfl
|
||||
@@ -210,7 +210,7 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
simp [hasAssignment, hl, getElem!, l_in_bounds, h2, hasNegAssignment, decidableGetElem?] at h5
|
||||
| both => simp (config := {decide := true}) only [h] at h3
|
||||
· intro k k_ne_j k_ne_l
|
||||
rw [Array.get_push]
|
||||
rw [Array.getElem_push]
|
||||
by_cases h : k.1 < units.size
|
||||
· simp only [h, dite_true]
|
||||
have k_ne_j : ⟨k.1, h⟩ ≠ j := by
|
||||
@@ -226,12 +226,12 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
exact k_ne_l rfl
|
||||
| false, true =>
|
||||
refine ⟨mostRecentUnitIdx, ⟨j.1, j_lt_updatedUnits_size⟩, i_gt_zero, ?_⟩
|
||||
simp [insertUnit, h5, ite_false, Array.get_push_eq, ne_eq]
|
||||
simp [insertUnit, h5, ite_false, Array.getElem_push_eq, ne_eq]
|
||||
constructor
|
||||
· simp [i_eq_l, ← hl]
|
||||
rfl
|
||||
· constructor
|
||||
· rw [Array.get_push_lt units l j.1 j.2, h1]
|
||||
· rw [Array.getElem_push_lt units l j.1 j.2, h1]
|
||||
· constructor
|
||||
· simp only [i_eq_l]
|
||||
rw [Array.getElem_modify_self]
|
||||
@@ -247,7 +247,7 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
| neg => simp (config := {decide := true}) only [h] at h3
|
||||
| both => simp (config := {decide := true}) only [h] at h3
|
||||
· intro k k_ne_l k_ne_j
|
||||
rw [Array.get_push]
|
||||
rw [Array.getElem_push]
|
||||
by_cases h : k.1 < units.size
|
||||
· simp only [h, dite_true]
|
||||
have k_ne_j : ⟨k.1, h⟩ ≠ j := by
|
||||
@@ -275,13 +275,13 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
refine ⟨⟨j.1, j_lt_updatedUnits_size⟩, b,i_gt_zero, ?_⟩
|
||||
simp only [insertUnit, h5, ite_false, reduceCtorEq]
|
||||
constructor
|
||||
· rw [Array.get_push_lt units l j.1 j.2, h1]
|
||||
· rw [Array.getElem_push_lt units l j.1 j.2, h1]
|
||||
· constructor
|
||||
· rw [Array.getElem_modify_of_ne (Ne.symm i_ne_l), h2]
|
||||
· constructor
|
||||
· exact h3
|
||||
· intro k k_ne_j
|
||||
rw [Array.get_push]
|
||||
rw [Array.getElem_push]
|
||||
by_cases h : k.val < units.size
|
||||
· simp only [h, dite_true]
|
||||
have k_ne_j : ⟨k.1, h⟩ ≠ j := by
|
||||
@@ -307,11 +307,11 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
constructor
|
||||
· split
|
||||
· exact h1
|
||||
· simp only [Array.get_push_lt units l j1.1 j1.2, h1]
|
||||
· simp only [Array.getElem_push_lt units l j1.1 j1.2, h1]
|
||||
· constructor
|
||||
· split
|
||||
· exact h2
|
||||
· simp only [Array.get_push_lt units l j2.1 j2.2, h2]
|
||||
· simp only [Array.getElem_push_lt units l j2.1 j2.2, h2]
|
||||
· constructor
|
||||
· split
|
||||
· exact h3
|
||||
@@ -336,7 +336,7 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
split
|
||||
· exact h5 ⟨k.1, k_in_bounds⟩ k_ne_j1 k_ne_j2
|
||||
· simp only [ne_eq]
|
||||
rw [Array.get_push]
|
||||
rw [Array.getElem_push]
|
||||
simp only [k_in_bounds, dite_true]
|
||||
exact h5 ⟨k.1, k_in_bounds⟩ k_ne_j1 k_ne_j2
|
||||
· next k_not_lt_units_size =>
|
||||
@@ -354,7 +354,7 @@ theorem insertUnitInvariant_insertUnit {n : Nat} (assignments0 : Array Assignmen
|
||||
rcases Nat.lt_or_eq_of_le <| Nat.le_of_lt_succ k_property with k_lt_units_size | k_eq_units_size
|
||||
· exfalso; exact k_not_lt_units_size k_lt_units_size
|
||||
· exact k_eq_units_size
|
||||
simp only [k_eq_units_size, Array.get_push_eq, ne_eq]
|
||||
simp only [k_eq_units_size, Array.getElem_push_eq, ne_eq]
|
||||
intro l_eq_i
|
||||
simp [getElem!, l_eq_i, i_in_bounds, h3, has_both, decidableGetElem?] at h
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Mac Malone
|
||||
import Lake.Build.Common
|
||||
|
||||
namespace Lake
|
||||
open System (FilePath)
|
||||
|
||||
/-! # Lean Executable Build
|
||||
The build function definition for a Lean executable.
|
||||
|
||||
@@ -16,7 +16,8 @@ definitions.
|
||||
-/
|
||||
|
||||
namespace Lake
|
||||
export System (SearchPath FilePath)
|
||||
open Lean (Name)
|
||||
open System (SearchPath FilePath)
|
||||
|
||||
/-- A dynamic/shared library for linking. -/
|
||||
structure Dynlib where
|
||||
|
||||
@@ -17,6 +17,7 @@ This module leverages the index to perform topologically-based recursive builds.
|
||||
|
||||
open Lean
|
||||
namespace Lake
|
||||
open System (FilePath)
|
||||
|
||||
/--
|
||||
Converts a conveniently-typed target facet build function into its
|
||||
|
||||
@@ -16,6 +16,7 @@ the build.
|
||||
-/
|
||||
|
||||
namespace Lake
|
||||
open Lean (Name)
|
||||
|
||||
/-- The type of Lake's build info. -/
|
||||
inductive BuildInfo
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Mac Malone
|
||||
import Lake.Util.Name
|
||||
|
||||
namespace Lake
|
||||
open Lean (Name)
|
||||
|
||||
/-- The type of keys in the Lake build store. -/
|
||||
inductive BuildKey
|
||||
|
||||
@@ -11,6 +11,7 @@ Build function definitions for a library's builtin facets.
|
||||
-/
|
||||
|
||||
namespace Lake
|
||||
open System (FilePath)
|
||||
|
||||
/-! ## Build Lean & Static Lib -/
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ Build function definitions for a package's builtin facets.
|
||||
|
||||
open System
|
||||
namespace Lake
|
||||
open Lean (Name)
|
||||
|
||||
/-- Compute a topological ordering of the package's transitive dependencies. -/
|
||||
def Package.recComputeDeps (self : Package) : FetchM (Array Package) := do
|
||||
|
||||
@@ -15,6 +15,7 @@ topological-based build of an initial key's dependencies).
|
||||
-/
|
||||
|
||||
namespace Lake
|
||||
open Lean (Name NameMap)
|
||||
|
||||
/-- A monad equipped with a Lake build store. -/
|
||||
abbrev MonadBuildStore (m) := MonadDStore BuildKey BuildData m
|
||||
|
||||
@@ -10,6 +10,8 @@ Utilities for fetching package, library, module, and executable targets and face
|
||||
-/
|
||||
|
||||
namespace Lake
|
||||
open Lean (Name)
|
||||
open System (FilePath)
|
||||
|
||||
/-! ## Package Facets & Targets -/
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@ import Lake.Build.Targets
|
||||
import Lake.CLI.Build
|
||||
|
||||
namespace Lake
|
||||
open Lean (Name)
|
||||
open System (FilePath)
|
||||
|
||||
def env (cmd : String) (args : Array String := #[]) : LakeT IO UInt32 := do
|
||||
IO.Process.spawn {cmd, args, env := ← getAugmentedEnv} >>= (·.wait)
|
||||
|
||||
@@ -7,6 +7,7 @@ import Lake.Build.Index
|
||||
import Lake.CLI.Error
|
||||
|
||||
namespace Lake
|
||||
open Lean (Name)
|
||||
|
||||
/-! ## Build Target Specifiers -/
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import Lake.Build.Actions
|
||||
|
||||
namespace Lake
|
||||
open Git System
|
||||
open Lean (Name)
|
||||
|
||||
/-- The default module of an executable in `std` package. -/
|
||||
def defaultExeRoot : Name := `Main
|
||||
@@ -126,7 +127,8 @@ package {repr pkgName} where
|
||||
version := v!\"0.1.0\"
|
||||
keywords := #[\"math\"]
|
||||
leanOptions := #[
|
||||
⟨`pp.unicode.fun, true⟩ -- pretty-prints `fun a ↦ b`
|
||||
⟨`pp.unicode.fun, true⟩, -- pretty-prints `fun a ↦ b`
|
||||
⟨`autoImplicit, false⟩
|
||||
]
|
||||
|
||||
require \"leanprover-community\" / \"mathlib\"
|
||||
@@ -144,6 +146,7 @@ defaultTargets = [{repr libRoot}]
|
||||
|
||||
[leanOptions]
|
||||
pp.unicode.fun = true # pretty-prints `fun a ↦ b`
|
||||
autoImplicit = false
|
||||
|
||||
[[require]]
|
||||
name = \"mathlib\"
|
||||
|
||||
@@ -19,7 +19,7 @@ import Lake.CLI.Serve
|
||||
-- # CLI
|
||||
|
||||
open System
|
||||
open Lean (Json toJson fromJson? LeanPaths)
|
||||
open Lean (Json toJson fromJson? LeanPaths NameMap)
|
||||
|
||||
namespace Lake
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import Lean.Util.FileSetupInfo
|
||||
|
||||
namespace Lake
|
||||
open Lean
|
||||
open System (FilePath)
|
||||
|
||||
/-- Exit code to return if `setup-file` cannot find the config file. -/
|
||||
def noConfigFileCode : ExitCode := 2
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Mac Malone
|
||||
import Lake.Config.Package
|
||||
|
||||
namespace Lake
|
||||
open Lean (Name)
|
||||
|
||||
/-- An external library -- its package plus its configuration. -/
|
||||
structure ExternLib where
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Mac Malone, Mario Carneiro
|
||||
import Lake.Build.Fetch
|
||||
|
||||
namespace Lake
|
||||
open Lean (Name)
|
||||
|
||||
/-- A facet's declarative configuration. -/
|
||||
structure FacetConfig (DataFam : Name → Type) (ι : Type) (name : Name) : Type where
|
||||
|
||||
@@ -7,7 +7,7 @@ import Lake.Config.Context
|
||||
import Lake.Config.Workspace
|
||||
|
||||
open System
|
||||
open Lean (Name)
|
||||
open Lean (Name NameMap)
|
||||
|
||||
/-! # Lake Configuration Monads
|
||||
Definitions and helpers for interacting with the Lake configuration monads.
|
||||
|
||||
@@ -6,6 +6,7 @@ Authors: Mac Malone
|
||||
import Lake.Build.Fetch
|
||||
|
||||
namespace Lake
|
||||
open Lean (Name)
|
||||
|
||||
/-- A custom target's declarative configuration. -/
|
||||
structure TargetConfig (pkgName name : Name) : Type where
|
||||
|
||||
@@ -12,6 +12,7 @@ import Lake.Util.Log
|
||||
open System
|
||||
|
||||
namespace Lake
|
||||
open Lean (Name)
|
||||
|
||||
/-- A Lake workspace -- the top-level package directory. -/
|
||||
structure Workspace : Type where
|
||||
|
||||
@@ -12,6 +12,7 @@ Macros for declaring Lake targets and facets.
|
||||
|
||||
namespace Lake.DSL
|
||||
open Lean Parser Command
|
||||
open System (FilePath)
|
||||
|
||||
syntax buildDeclSig :=
|
||||
identOrStr (ppSpace simpleBinder)? Term.typeSpec declValSimple
|
||||
|
||||
@@ -15,6 +15,7 @@ from Lake configuration file (either Lean or TOML).
|
||||
open Lean
|
||||
|
||||
namespace Lake
|
||||
open System (FilePath)
|
||||
|
||||
/--
|
||||
Return whether a configuration file with the given name
|
||||
|
||||
@@ -17,6 +17,7 @@ Lake configuration file written in TOML.
|
||||
-/
|
||||
|
||||
namespace Lake
|
||||
open System (FilePath)
|
||||
|
||||
open Toml
|
||||
|
||||
|
||||
@@ -11,8 +11,7 @@ import Lake.Util.RBArray
|
||||
open Lean
|
||||
|
||||
namespace Lake
|
||||
|
||||
export Lean (Name NameMap)
|
||||
open Lean (Name NameMap)
|
||||
|
||||
/--
|
||||
First tries to convert a string into a legal name.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user