ZAIDX11 commited on
Commit
c4e3b10
Β·
verified Β·
1 Parent(s): d705e59

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes. Β  See raw diff
Files changed (50) hide show
  1. .gitattributes +27 -0
  2. backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Do/WP/Basic.olean +3 -0
  3. backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Internal/UV/System.olean +3 -0
  4. backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Tactic/BVDecide/Bitblast/BVExpr/Circuit/Lemmas/Operations/Replicate.olean +3 -0
  5. backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Time/DateTime/PlainDateTime.olean +3 -0
  6. backend/core/leanprover--lean4---v4.22.0/src/lean/Init/Grind/Ordered/Order.lean +118 -0
  7. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Data/Lsp/Utf16.lean +120 -0
  8. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Data/Lsp/Window.lean +48 -0
  9. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Data/Lsp/Workspace.lean +73 -0
  10. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Data/Xml/Basic.lean +41 -0
  11. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Data/Xml/Parser.lean +487 -0
  12. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/DocString/Add.lean +61 -0
  13. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/DocString/Extension.lean +81 -0
  14. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/DocString/Links.lean +171 -0
  15. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/App.lean +1854 -0
  16. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Arg.lean +68 -0
  17. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Attributes.lean +71 -0
  18. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/AutoBound.lean +51 -0
  19. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/AuxDef.lean +36 -0
  20. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/BinderPredicates.lean +43 -0
  21. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Binders.lean +957 -0
  22. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/BindersUtil.lean +73 -0
  23. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/BuiltinCommand.lean +676 -0
  24. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/BuiltinEvalCommand.lean +277 -0
  25. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/BuiltinNotation.lean +534 -0
  26. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/BuiltinTerm.lean +386 -0
  27. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Calc.lean +174 -0
  28. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/CheckTactic.lean +86 -0
  29. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Command.lean +891 -0
  30. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/ComputedFields.lean +246 -0
  31. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Config.lean +61 -0
  32. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/DeclModifiers.lean +306 -0
  33. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/DeclNameGen.lean +264 -0
  34. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/DeclUtil.lean +86 -0
  35. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Declaration.lean +347 -0
  36. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/DeclarationRange.lean +71 -0
  37. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/DefView.lean +232 -0
  38. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Deriving.lean +19 -0
  39. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Do.lean +1827 -0
  40. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/ElabRules.lean +102 -0
  41. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/ErrorExplanation.lean +138 -0
  42. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Eval.lean +20 -0
  43. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Exception.lean +68 -0
  44. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Extra.lean +588 -0
  45. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Frontend.lean +218 -0
  46. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/GenInjective.lean +17 -0
  47. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/GuardMsgs.lean +235 -0
  48. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Import.lean +101 -0
  49. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Inductive.lean +301 -0
  50. backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/InfoTree.lean +9 -0
.gitattributes CHANGED
@@ -4432,3 +4432,30 @@ backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Sat/AIG/RelabelNat.olean f
4432
  backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Do/PostCond.olean filter=lfs diff=lfs merge=lfs -text
4433
  external/alphageometry/.venv-ag/Lib/site-packages/scipy/fftpack/tests/fftw_double_ref.npz filter=lfs diff=lfs merge=lfs -text
4434
  external/alphageometry/.venv-ag/Lib/site-packages/scipy/fftpack/tests/fftw_longdouble_ref.npz filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4432
  backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Do/PostCond.olean filter=lfs diff=lfs merge=lfs -text
4433
  external/alphageometry/.venv-ag/Lib/site-packages/scipy/fftpack/tests/fftw_double_ref.npz filter=lfs diff=lfs merge=lfs -text
4434
  external/alphageometry/.venv-ag/Lib/site-packages/scipy/fftpack/tests/fftw_longdouble_ref.npz filter=lfs diff=lfs merge=lfs -text
4435
+ external/alphageometry/.venv-ag/Scripts/f2py.exe filter=lfs diff=lfs merge=lfs -text
4436
+ external/alphageometry/.venv-ag/Scripts/fonttools.exe filter=lfs diff=lfs merge=lfs -text
4437
+ external/alphageometry/.venv-ag/Scripts/numpy-config.exe filter=lfs diff=lfs merge=lfs -text
4438
+ external/alphageometry/.venv-ag/Scripts/pip.exe filter=lfs diff=lfs merge=lfs -text
4439
+ external/alphageometry/.venv-ag/Scripts/pip3.10.exe filter=lfs diff=lfs merge=lfs -text
4440
+ external/alphageometry/.venv-ag/Scripts/pip3.exe filter=lfs diff=lfs merge=lfs -text
4441
+ external/alphageometry/.venv-ag/Scripts/pyftmerge.exe filter=lfs diff=lfs merge=lfs -text
4442
+ external/alphageometry/.venv-ag/Scripts/pyftsubset.exe filter=lfs diff=lfs merge=lfs -text
4443
+ external/alphageometry/.venv-ag/Scripts/python.exe filter=lfs diff=lfs merge=lfs -text
4444
+ external/alphageometry/.venv-ag/Scripts/pythonw.exe filter=lfs diff=lfs merge=lfs -text
4445
+ external/alphageometry/.venv-ag/Scripts/ttx.exe filter=lfs diff=lfs merge=lfs -text
4446
+ external/alphageometry/.venv-ag/Scripts/wheel.exe filter=lfs diff=lfs merge=lfs -text
4447
+ backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Internal/UV/System.olean filter=lfs diff=lfs merge=lfs -text
4448
+ backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Time/DateTime/PlainDateTime.olean filter=lfs diff=lfs merge=lfs -text
4449
+ backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Do/WP/Basic.olean filter=lfs diff=lfs merge=lfs -text
4450
+ backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Tactic/BVDecide/Bitblast/BVExpr/Circuit/Lemmas/Operations/Replicate.olean filter=lfs diff=lfs merge=lfs -text
4451
+ external/alphageometry/meliad_lib/meliad/transformer/vocabs/pg19train_bpe_1000.model filter=lfs diff=lfs merge=lfs -text
4452
+ external/alphageometry/meliad_lib/meliad/transformer/vocabs/pg19train_bpe_128000.model filter=lfs diff=lfs merge=lfs -text
4453
+ external/alphageometry/meliad_lib/meliad/transformer/vocabs/pg19train_bpe_32000.model filter=lfs diff=lfs merge=lfs -text
4454
+ external/alphageometry/meliad_lib/meliad/transformer/vocabs/pg19train_bpe_4000.model filter=lfs diff=lfs merge=lfs -text
4455
+ external/alphageometry/meliad_lib/meliad/transformer/vocabs/pg19train_bpe_512.model filter=lfs diff=lfs merge=lfs -text
4456
+ external/alphageometry/meliad_lib/meliad/transformer/vocabs/pg19train_bpe_64000.model filter=lfs diff=lfs merge=lfs -text
4457
+ external/alphageometry/meliad_lib/meliad/transformer/vocabs/pg19train_bpe_8000.model filter=lfs diff=lfs merge=lfs -text
4458
+ external/alphageometry/meliad_lib/meliad/transformer/vocabs/pg19train_bpe_96000.model filter=lfs diff=lfs merge=lfs -text
4459
+ frontend/file_00000000bcfc624381c37949ccd77bc9.png filter=lfs diff=lfs merge=lfs -text
4460
+ frontend/file_00000000cf6462469688bc5199fed92b.png filter=lfs diff=lfs merge=lfs -text
4461
+ frontend/IMG_20250618_170452.jpg filter=lfs diff=lfs merge=lfs -text
backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Do/WP/Basic.olean ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e9ec7a91d4d492bea4023c88138e4274ad0fd17c51385ffb706b56b7dd945576
3
+ size 301128
backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Internal/UV/System.olean ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d18b1027d6e9c1432697fa689cc21ba16dc92f429e56e440f58a319cce295c74
3
+ size 736624
backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Tactic/BVDecide/Bitblast/BVExpr/Circuit/Lemmas/Operations/Replicate.olean ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ea58b608189883e9ec75733caae606328846567f9444b65e130f6f56a7c95dd6
3
+ size 324992
backend/core/leanprover--lean4---v4.22.0/lib/lean/Std/Time/DateTime/PlainDateTime.olean ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:45800e87fb690735a4ea0044e72e1c7b31b1a4e05854b3d0d66b1e28c04eaab0
3
+ size 704216
backend/core/leanprover--lean4---v4.22.0/src/lean/Init/Grind/Ordered/Order.lean ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2025 Lean FRO, LLC. or its affiliates. All Rights Reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Kim Morrison
5
+ -/
6
+ module
7
+
8
+ prelude
9
+ public import Init.Data.Int.Order
10
+
11
+ public section
12
+
13
+ namespace Lean.Grind
14
+
15
+ /-- A preorder is a reflexive, transitive relation `≀` with `a < b` defined in the obvious way. -/
16
+ class Preorder (Ξ± : Type u) extends LE Ξ±, LT Ξ± where
17
+ /-- The less-than-or-equal relation is reflexive. -/
18
+ le_refl : βˆ€ a : Ξ±, a ≀ a
19
+ /-- The less-than-or-equal relation is transitive. -/
20
+ le_trans : βˆ€ {a b c : Ξ±}, a ≀ b β†’ b ≀ c β†’ a ≀ c
21
+ lt := fun a b => a ≀ b ∧ Β¬b ≀ a
22
+ /-- The less-than relation is determined by the less-than-or-equal relation. -/
23
+ lt_iff_le_not_le : βˆ€ {a b : Ξ±}, a < b ↔ a ≀ b ∧ Β¬b ≀ a := by intros; rfl
24
+
25
+ namespace Preorder
26
+
27
+ variable {Ξ± : Type u} [Preorder Ξ±]
28
+
29
+ theorem le_of_lt {a b : Ξ±} (h : a < b) : a ≀ b := (lt_iff_le_not_le.mp h).1
30
+
31
+ theorem lt_of_lt_of_le {a b c : Ξ±} (h₁ : a < b) (hβ‚‚ : b ≀ c) : a < c := by
32
+ simp [lt_iff_le_not_le] at h₁ ⊒
33
+ exact ⟨le_trans h₁.1 hβ‚‚, fun h => h₁.2 (le_trans hβ‚‚ h)⟩
34
+
35
+ theorem lt_of_le_of_lt {a b c : Ξ±} (h₁ : a ≀ b) (hβ‚‚ : b < c) : a < c := by
36
+ simp [lt_iff_le_not_le] at hβ‚‚ ⊒
37
+ exact ⟨le_trans h₁ hβ‚‚.1, fun h => hβ‚‚.2 (le_trans h h₁)⟩
38
+
39
+ theorem lt_trans {a b c : Ξ±} (h₁ : a < b) (hβ‚‚ : b < c) : a < c :=
40
+ lt_of_lt_of_le h₁ (le_of_lt hβ‚‚)
41
+
42
+ theorem lt_irrefl (a : Ξ±) : Β¬ (a < a) := by
43
+ intro h
44
+ simp [lt_iff_le_not_le] at h
45
+
46
+ theorem ne_of_lt {a b : Ξ±} (h : a < b) : a β‰  b :=
47
+ fun w => lt_irrefl a (w.symm β–Έ h)
48
+
49
+ theorem ne_of_gt {a b : Ξ±} (h : a > b) : a β‰  b :=
50
+ fun w => lt_irrefl b (w.symm β–Έ h)
51
+
52
+ theorem not_ge_of_lt {a b : Ξ±} (h : a < b) : Β¬b ≀ a :=
53
+ fun w => lt_irrefl a (lt_of_lt_of_le h w)
54
+
55
+ theorem not_gt_of_lt {a b : Ξ±} (h : a < b) : Β¬a > b :=
56
+ fun w => lt_irrefl a (lt_trans h w)
57
+
58
+ end Preorder
59
+
60
+ /-- A partial order is a preorder with the additional property that `a ≀ b` and `b ≀ a` implies `a = b`. -/
61
+ class PartialOrder (Ξ± : Type u) extends Preorder Ξ± where
62
+ /-- The less-than-or-equal relation is antisymmetric. -/
63
+ le_antisymm : βˆ€ {a b : Ξ±}, a ≀ b β†’ b ≀ a β†’ a = b
64
+
65
+ namespace PartialOrder
66
+
67
+ variable {Ξ± : Type u} [PartialOrder Ξ±]
68
+
69
+ theorem le_iff_lt_or_eq {a b : Ξ±} : a ≀ b ↔ a < b ∨ a = b := by
70
+ constructor
71
+ Β· intro h
72
+ rw [Preorder.lt_iff_le_not_le, Classical.or_iff_not_imp_right]
73
+ exact fun w => ⟨h, fun w' => w (le_antisymm h w')⟩
74
+ Β· intro h
75
+ cases h with
76
+ | inl h => exact Preorder.le_of_lt h
77
+ | inr h => subst h; exact Preorder.le_refl a
78
+
79
+ end PartialOrder
80
+
81
+ /-- A linear order is a partial order with the additional property that every pair of elements is comparable. -/
82
+ class LinearOrder (Ξ± : Type u) extends PartialOrder Ξ± where
83
+ /-- For every two elements `a` and `b`, either `a ≀ b` or `b ≀ a`. -/
84
+ le_total : βˆ€ a b : Ξ±, a ≀ b ∨ b ≀ a
85
+
86
+ namespace LinearOrder
87
+
88
+ variable {Ξ± : Type u} [LinearOrder Ξ±]
89
+
90
+ theorem trichotomy (a b : α) : a < b ∨ a = b ∨ b < a := by
91
+ cases LinearOrder.le_total a b with
92
+ | inl h =>
93
+ rw [PartialOrder.le_iff_lt_or_eq] at h
94
+ cases h with
95
+ | inl h => left; exact h
96
+ | inr h => right; left; exact h
97
+ | inr h =>
98
+ rw [PartialOrder.le_iff_lt_or_eq] at h
99
+ cases h with
100
+ | inl h => right; right; exact h
101
+ | inr h => right; left; exact h.symm
102
+
103
+ theorem le_of_not_lt {Ξ±} [LinearOrder Ξ±] {a b : Ξ±} (h : Β¬ a < b) : b ≀ a := by
104
+ cases LinearOrder.trichotomy a b
105
+ next => contradiction
106
+ next h => apply PartialOrder.le_iff_lt_or_eq.mpr; cases h <;> simp [*]
107
+
108
+ theorem lt_of_not_le {Ξ±} [LinearOrder Ξ±] {a b : Ξ±} (h : Β¬ a ≀ b) : b < a := by
109
+ cases LinearOrder.trichotomy a b
110
+ next h₁ hβ‚‚ => have := Preorder.lt_iff_le_not_le.mp hβ‚‚; simp [h] at this
111
+ next h =>
112
+ cases h
113
+ next h => subst a; exact False.elim <| h (Preorder.le_refl b)
114
+ next => assumption
115
+
116
+ end LinearOrder
117
+
118
+ end Lean.Grind
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Data/Lsp/Utf16.lean ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2020 Marc Huisinga. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+
5
+ Authors: Marc Huisinga, Wojciech Nawrocki
6
+ -/
7
+ prelude
8
+ import Init.Data.String
9
+ import Lean.Data.Lsp.Basic
10
+ import Lean.Data.Position
11
+ import Lean.DeclarationRange
12
+
13
+ /-! LSP uses UTF-16 for indexing, so we need to provide some primitives
14
+ to interact with Lean strings using UTF-16 indices. -/
15
+
16
+ namespace Char
17
+
18
+ /-- Returns the number of bytes required to encode this `Char` in UTF-16. -/
19
+ def utf16Size (c : Char) : UInt32 :=
20
+ if c.val ≀ 0xFFFF then 1 else 2
21
+
22
+ end Char
23
+
24
+ namespace String
25
+
26
+ private def csize16 (c : Char) : Nat :=
27
+ c.utf16Size.toNat
28
+
29
+ def utf16Length (s : String) : Nat :=
30
+ s.foldr (fun c acc => csize16 c + acc) 0
31
+
32
+ private def codepointPosToUtf16PosFromAux (s : String) : Nat β†’ Pos β†’ Nat β†’ Nat
33
+ | 0, _, utf16pos => utf16pos
34
+ | cp+1, utf8pos, utf16pos => codepointPosToUtf16PosFromAux s cp (s.next utf8pos) (utf16pos + csize16 (s.get utf8pos))
35
+
36
+ /-- Computes the UTF-16 offset of the `n`-th Unicode codepoint
37
+ in the substring of `s` starting at UTF-8 offset `off`.
38
+ Yes, this is actually useful.-/
39
+ def codepointPosToUtf16PosFrom (s : String) (n : Nat) (off : Pos) : Nat :=
40
+ codepointPosToUtf16PosFromAux s n off 0
41
+
42
+ def codepointPosToUtf16Pos (s : String) (pos : Nat) : Nat :=
43
+ codepointPosToUtf16PosFrom s pos 0
44
+
45
+ private partial def utf16PosToCodepointPosFromAux (s : String) : Nat β†’ Pos β†’ Nat β†’ Nat
46
+ | 0, _, cp => cp
47
+ | utf16pos, utf8pos, cp => utf16PosToCodepointPosFromAux s (utf16pos - csize16 (s.get utf8pos)) (s.next utf8pos) (cp + 1)
48
+
49
+ /-- Computes the position of the Unicode codepoint at UTF-16 offset
50
+ `utf16pos` in the substring of `s` starting at UTF-8 offset `off`. -/
51
+ def utf16PosToCodepointPosFrom (s : String) (utf16pos : Nat) (off : Pos) : Nat :=
52
+ utf16PosToCodepointPosFromAux s utf16pos off 0
53
+
54
+ def utf16PosToCodepointPos (s : String) (pos : Nat) : Nat :=
55
+ utf16PosToCodepointPosFrom s pos 0
56
+
57
+ /-- Starting at `utf8pos`, finds the UTF-8 offset of the `p`-th codepoint. -/
58
+ def codepointPosToUtf8PosFrom (s : String) : String.Pos β†’ Nat β†’ String.Pos
59
+ | utf8pos, 0 => utf8pos
60
+ | utf8pos, p+1 => codepointPosToUtf8PosFrom s (s.next utf8pos) p
61
+
62
+ end String
63
+
64
+ namespace Lean
65
+ namespace FileMap
66
+
67
+ private def lineStartPos (text : FileMap) (line : Nat) : String.Pos :=
68
+ if h : line < text.positions.size then
69
+ text.positions[line]
70
+ else if text.positions.isEmpty then
71
+ 0
72
+ else
73
+ text.positions.back!
74
+
75
+ /-- Computes an UTF-8 offset into `text.source`
76
+ from an LSP-style 0-indexed (ln, col) position. -/
77
+ def lspPosToUtf8Pos (text : FileMap) (pos : Lsp.Position) : String.Pos :=
78
+ let lineStartPos := lineStartPos text pos.line
79
+ let chr := text.source.utf16PosToCodepointPosFrom pos.character lineStartPos
80
+ text.source.codepointPosToUtf8PosFrom lineStartPos chr
81
+
82
+ def leanPosToLspPos (text : FileMap) : Lean.Position β†’ Lsp.Position
83
+ | ⟨line, col⟩ =>
84
+ ⟨line - 1, text.source.codepointPosToUtf16PosFrom col (lineStartPos text (line - 1))⟩
85
+
86
+ def utf8PosToLspPos (text : FileMap) (pos : String.Pos) : Lsp.Position :=
87
+ text.leanPosToLspPos (text.toPosition pos)
88
+
89
+ /-- Gets the LSP range from a `String.Range`. -/
90
+ def utf8RangeToLspRange (text : FileMap) (range : String.Range) : Lsp.Range :=
91
+ { start := text.utf8PosToLspPos range.start, Β«endΒ» := text.utf8PosToLspPos range.stop }
92
+
93
+ def lspRangeToUtf8Range (text : FileMap) (range : Lsp.Range) : String.Range :=
94
+ { start := text.lspPosToUtf8Pos range.start, stop := text.lspPosToUtf8Pos range.end }
95
+
96
+ end FileMap
97
+
98
+ def DeclarationRange.ofFilePositions (text : FileMap) (pos : Position) (endPos : Position)
99
+ : DeclarationRange := {
100
+ pos,
101
+ charUtf16 := text.leanPosToLspPos pos |>.character
102
+ endPos,
103
+ endCharUtf16 := text.leanPosToLspPos endPos |>.character
104
+ }
105
+
106
+ def DeclarationRange.ofStringPositions (text : FileMap) (pos : String.Pos) (endPos : String.Pos)
107
+ : DeclarationRange :=
108
+ .ofFilePositions text (text.toPosition pos) (text.toPosition endPos)
109
+
110
+ /--
111
+ Convert the Lean `DeclarationRange` to an LSP `Range` by turning the 1-indexed line numbering into a
112
+ 0-indexed line numbering and converting the character offset within the line to a UTF-16 indexed
113
+ offset.
114
+ -/
115
+ def DeclarationRange.toLspRange (r : DeclarationRange) : Lsp.Range := {
116
+ start := ⟨r.pos.line - 1, r.charUtf16⟩
117
+ «end» := ⟨r.endPos.line - 1, r.endCharUtf16⟩
118
+ }
119
+
120
+ end Lean
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Data/Lsp/Window.lean ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Marc Huisinga
5
+ -/
6
+ prelude
7
+ import Lean.Data.Json
8
+
9
+ open Lean
10
+
11
+ inductive MessageType where
12
+ | error
13
+ | warning
14
+ | info
15
+ | log
16
+
17
+ instance : FromJson MessageType where
18
+ fromJson?
19
+ | (1 : Nat) => .ok .error
20
+ | (2 : Nat) => .ok .warning
21
+ | (3 : Nat) => .ok .info
22
+ | (4 : Nat) => .ok .log
23
+ | _ => .error "Unknown MessageType ID"
24
+
25
+ instance : ToJson MessageType where
26
+ toJson
27
+ | .error => 1
28
+ | .warning => 2
29
+ | .info => 3
30
+ | .log => 4
31
+
32
+ structure ShowMessageParams where
33
+ type : MessageType
34
+ message : String
35
+ deriving FromJson, ToJson
36
+
37
+ structure MessageActionItem where
38
+ title : String
39
+ deriving FromJson, ToJson
40
+
41
+ structure ShowMessageRequestParams where
42
+ type : MessageType
43
+ message : String
44
+ actions? : Option (Array MessageActionItem)
45
+ deriving FromJson, ToJson
46
+
47
+ def ShowMessageResponse := Option MessageActionItem
48
+ deriving FromJson, ToJson
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Data/Lsp/Workspace.lean ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2020 Wojciech Nawrocki. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+
5
+ Authors: Wojciech Nawrocki
6
+ -/
7
+ prelude
8
+ import Lean.Data.Lsp.Basic
9
+ import Lean.Data.Json
10
+
11
+ namespace Lean
12
+ namespace Lsp
13
+
14
+ open Json
15
+
16
+ structure WorkspaceFolder where
17
+ uri : DocumentUri
18
+ name : String
19
+ deriving ToJson, FromJson
20
+
21
+ -- TODO(WN):
22
+ -- WorkspaceFoldersServerCapabilities,
23
+ -- DidChangeWorkspaceFoldersParams,
24
+ -- WorkspaceFoldersChangeEvent
25
+
26
+ structure FileSystemWatcher where
27
+ globPattern : String
28
+ kind : Option Nat := none
29
+ deriving FromJson, ToJson
30
+
31
+ namespace FileSystemWatcher
32
+
33
+ -- Bit flags for `FileSystemWatcher.kind`
34
+ def create := 1
35
+ def change := 2
36
+ def delete := 4
37
+
38
+ end FileSystemWatcher
39
+
40
+ structure DidChangeWatchedFilesRegistrationOptions where
41
+ watchers : Array FileSystemWatcher
42
+ deriving FromJson, ToJson
43
+
44
+ inductive FileChangeType
45
+ | Created
46
+ | Changed
47
+ | Deleted
48
+
49
+ instance : FromJson FileChangeType where
50
+ fromJson? j := do
51
+ match (← fromJson? j : Nat) with
52
+ | 1 => return FileChangeType.Created
53
+ | 2 => return FileChangeType.Changed
54
+ | 3 => return FileChangeType.Deleted
55
+ | _ => throw s!"expected 1, 2, or 3, got {j}"
56
+
57
+ instance : ToJson FileChangeType where
58
+ toJson
59
+ | FileChangeType.Created => toJson 1
60
+ | FileChangeType.Changed => toJson 2
61
+ | FileChangeType.Deleted => toJson 3
62
+
63
+ structure FileEvent where
64
+ uri : DocumentUri
65
+ type : FileChangeType
66
+ deriving FromJson, ToJson
67
+
68
+ structure DidChangeWatchedFilesParams where
69
+ changes : Array FileEvent
70
+ deriving FromJson, ToJson
71
+
72
+ end Lsp
73
+ end Lean
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Data/Xml/Basic.lean ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Author: Dany Fabian
5
+ -/
6
+ prelude
7
+ import Lean.Data.RBMap
8
+ import Init.Data.ToString.Macro
9
+
10
+ namespace Lean
11
+ namespace Xml
12
+
13
+ def Attributes := RBMap String String compare
14
+ instance : ToString Attributes := ⟨λ as => as.fold (λ s n v => s ++ s!" {n}=\"{v}\"") ""⟩
15
+
16
+ mutual
17
+ inductive Element
18
+ | Element
19
+ (name : String)
20
+ (attributes : Attributes)
21
+ (content : Array Content)
22
+
23
+ inductive Content
24
+ | Element (element : Element)
25
+ | Comment (comment : String)
26
+ | Character (content : String)
27
+ deriving Inhabited
28
+ end
29
+
30
+ mutual
31
+ private partial def eToString : Element β†’ String
32
+ | Element.Element n a c => s!"<{n}{a}>{c.map cToString |>.foldl (Β· ++ Β·) ""}</{n}>"
33
+
34
+ private partial def cToString : Content β†’ String
35
+ | Content.Element e => eToString e
36
+ | Content.Comment c => s!"<!--{c}-->"
37
+ | Content.Character c => c
38
+
39
+ end
40
+ instance : ToString Element := ⟨eToString⟩
41
+ instance : ToString Content := ⟨cToString⟩
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Data/Xml/Parser.lean ADDED
@@ -0,0 +1,487 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Author: Dany Fabian
5
+ -/
6
+ prelude
7
+ import Std.Internal.Parsec
8
+ import Lean.Data.Xml.Basic
9
+
10
+ open System
11
+ open Lean
12
+
13
+ namespace Lean
14
+ namespace Xml
15
+
16
+ open Std.Internal.Parsec
17
+ open Std.Internal.Parsec.String
18
+
19
+ namespace Parser
20
+
21
+ abbrev LeanChar := Char
22
+
23
+ /-- consume a newline character sequence pretending, that we read '\n'. As per spec:
24
+ https://www.w3.org/TR/xml/#sec-line-ends -/
25
+ def endl : Parser LeanChar := (skipString "\r\n" <|> skipChar '\r' <|> skipChar '\n') *> pure '\n'
26
+
27
+ def quote (p : Parser Ξ±) : Parser Ξ± :=
28
+ skipChar '\'' *> p <* skipChar '\''
29
+ <|> skipChar '"' *> p <* skipChar '"'
30
+
31
+ /-- https://www.w3.org/TR/xml/#NT-Char -/
32
+ def Char : Parser LeanChar :=
33
+ (attempt do
34
+ let c ← any
35
+ let cNat := c.toNat
36
+ if (0x20 ≀ cNat ∧ cNat ≀ 0xD7FF)
37
+ ∨ (0xE000 ≀ cNat ∧ cNat ≀ 0xFFFD)
38
+ ∨ (0x10000 ≀ cNat ∧ cNat ≀ 0x10FFFF) then pure c else fail "expected xml char")
39
+ <|> pchar '\t' <|> endl
40
+
41
+ /-- https://www.w3.org/TR/xml/#NT-S -/
42
+ def S : Parser String :=
43
+ many1Chars (pchar ' ' <|> endl <|> pchar '\t')
44
+
45
+ /-- https://www.w3.org/TR/xml/#NT-Eq -/
46
+ def Eq : Parser Unit :=
47
+ optional S *> skipChar '=' <* optional S
48
+
49
+ private def nameStartCharRanges : Array (Nat Γ— Nat) :=
50
+ #[(0xC0, 0xD6),
51
+ (0xD8, 0xF6),
52
+ (0xF8, 0x2FF),
53
+ (0x370, 0x37D),
54
+ (0x37F, 0x1FFF),
55
+ (0x200C, 0x200D),
56
+ (0x2070, 0x218F),
57
+ (0x2C00, 0x2FEF),
58
+ (0x3001, 0xD7FF),
59
+ (0xF900, 0xFDCF),
60
+ (0xFDF0, 0xFFFD),
61
+ (0x10000, 0xEFFFF)]
62
+
63
+ /-- https://www.w3.org/TR/xml/#NT-NameStartChar -/
64
+ def NameStartChar : Parser LeanChar := attempt do
65
+ let c ← any
66
+ if ('A' ≀ c ∧ c ≀ 'Z') ∨ ('a' ≀ c ∧ c ≀ 'z') then pure c
67
+ else if c = ':' ∨ c = '_' then pure c
68
+ else
69
+ let cNum := c.toNat
70
+ if nameStartCharRanges.any (fun (lo, hi) => lo ≀ cNum ∧ cNum ≀ hi) then pure c
71
+ else fail "expected a name character"
72
+
73
+ /-- https://www.w3.org/TR/xml/#NT-NameChar -/
74
+ def NameChar : Parser LeanChar :=
75
+ NameStartChar <|> digit <|> pchar '-' <|> pchar '.' <|> pchar '\xB7'
76
+ <|> satisfy (Ξ» c => ('\u0300' ≀ c ∧ c ≀ '\u036F') ∨ ('\u203F' ≀ c ∧ c ≀ '\u2040'))
77
+
78
+ /-- https://www.w3.org/TR/xml/#NT-Name -/
79
+ def Name : Parser String := do
80
+ let x ← NameStartChar
81
+ manyCharsCore NameChar x.toString
82
+
83
+ /-- https://www.w3.org/TR/xml/#NT-VersionNum -/
84
+ def VersionNum : Parser Unit :=
85
+ skipString "1." <* (many1 digit)
86
+
87
+ /-- https://www.w3.org/TR/xml/#NT-VersionInfo -/
88
+ def VersionInfo : Parser Unit := do
89
+ S *>
90
+ skipString "version"
91
+ Eq
92
+ quote VersionNum
93
+
94
+ /-- https://www.w3.org/TR/xml/#NT-EncName -/
95
+ def EncName : Parser String := do
96
+ let x ← asciiLetter
97
+ manyCharsCore (asciiLetter <|> digit <|> pchar '-' <|> pchar '_' <|> pchar '.') x.toString
98
+
99
+ /-- https://www.w3.org/TR/xml/#NT-EncodingDecl -/
100
+ def EncodingDecl : Parser String := do
101
+ S *>
102
+ skipString "encoding"
103
+ Eq
104
+ quote EncName
105
+
106
+ /-- https://www.w3.org/TR/xml/#NT-SDDecl -/
107
+ def SDDecl : Parser String := do
108
+ S *> skipString "standalone" *> Eq *> quote (pstring "yes" <|> pstring "no")
109
+
110
+ /-- https://www.w3.org/TR/xml/#NT-XMLDecl -/
111
+ def XMLdecl : Parser Unit := do
112
+ skipString "<?xml"
113
+ VersionInfo
114
+ optional EncodingDecl *>
115
+ optional SDDecl *>
116
+ optional S *>
117
+ skipString "?>"
118
+
119
+ /-- https://www.w3.org/TR/xml/#NT-Comment -/
120
+ def Comment : Parser String :=
121
+ let notDash := Char.toString <$> satisfy (Ξ» c => c β‰  '-')
122
+ skipString "<!--" *>
123
+ Array.foldl String.append "" <$> many (attempt <| notDash <|> (do
124
+ let d ← pchar '-'
125
+ let c ← notDash
126
+ pure $ d.toString ++ c))
127
+ <* skipString "-->"
128
+
129
+ /-- https://www.w3.org/TR/xml/#NT-PITarget -/
130
+ def PITarget : Parser String :=
131
+ Name <* (skipChar 'X' <|> skipChar 'x') <* (skipChar 'M' <|> skipChar 'm') <* (skipChar 'L' <|> skipChar 'l')
132
+
133
+ /-- https://www.w3.org/TR/xml/#NT-PI -/
134
+ def PI : Parser Unit := do
135
+ skipString "<?"
136
+ <* PITarget <*
137
+ optional (S *> manyChars (notFollowedBy (skipString "?>") *> Char))
138
+ skipString "?>"
139
+
140
+ /-- https://www.w3.org/TR/xml/#NT-Misc -/
141
+ def Misc : Parser Unit :=
142
+ Comment *> pure () <|> PI <|> S *> pure ()
143
+
144
+ /-- https://www.w3.org/TR/xml/#NT-SystemLiteral -/
145
+ def SystemLiteral : Parser String :=
146
+ pchar '"' *> manyChars (satisfy Ξ» c => c β‰  '"') <* pchar '"'
147
+ <|> pchar '\'' *> manyChars (satisfy Ξ» c => c β‰  '\'') <* pure '\''
148
+
149
+ /-- https://www.w3.org/TR/xml/#NT-PubidChar -/
150
+ def PubidChar : Parser LeanChar :=
151
+ asciiLetter <|> digit <|> endl <|> attempt do
152
+ let c ← any
153
+ if "-'()+,./:=?;!*#@$_%".contains c then pure c else fail "PublidChar expected"
154
+
155
+ /-- https://www.w3.org/TR/xml/#NT-PubidLiteral -/
156
+ def PubidLiteral : Parser String :=
157
+ pchar '"' *> manyChars PubidChar <* pchar '"'
158
+ <|> pchar '\'' *> manyChars (attempt do
159
+ let c ← PubidChar
160
+ if c = '\'' then fail "'\\'' not expected" else pure c) <* pchar '\''
161
+
162
+ /-- https://www.w3.org/TR/xml/#NT-ExternalID -/
163
+ def ExternalID : Parser Unit :=
164
+ skipString "SYSTEM" *> S *> SystemLiteral *> pure ()
165
+ <|> skipString "PUBLIC" *> S *> PubidLiteral *> S *> SystemLiteral *> pure ()
166
+
167
+ /-- https://www.w3.org/TR/xml/#NT-Mixed -/
168
+ def Mixed : Parser Unit :=
169
+ (do
170
+ skipChar '('
171
+ optional S *>
172
+ skipString "#PCDATA" *>
173
+ many (optional S *> skipChar '|' *> optional S *> Name) *>
174
+ optional S *>
175
+ skipString ")*")
176
+ <|> skipChar '(' *> (optional S) *> skipString "#PCDATA" <* (optional S) <* skipChar ')'
177
+
178
+ mutual
179
+ /-- https://www.w3.org/TR/xml/#NT-cp -/
180
+ partial def cp : Parser Unit :=
181
+ (Name *> pure () <|> choice <|> seq) <* optional (skipChar '?' <|> skipChar '*' <|> skipChar '+')
182
+
183
+ /-- https://www.w3.org/TR/xml/#NT-choice -/
184
+ partial def choice : Parser Unit := do
185
+ skipChar '('
186
+ optional S *>
187
+ cp
188
+ many1 (optional S *> skipChar '|' *> optional S *> cp) *>
189
+ optional S *>
190
+ skipChar ')'
191
+
192
+ /-- https://www.w3.org/TR/xml/#NT-seq -/
193
+ partial def seq : Parser Unit := do
194
+ skipChar '('
195
+ optional S *>
196
+ cp
197
+ many (optional S *> skipChar ',' *> optional S *> cp) *>
198
+ optional S *>
199
+ skipChar ')'
200
+ end
201
+
202
+ /-- https://www.w3.org/TR/xml/#NT-children -/
203
+ def children : Parser Unit :=
204
+ (choice <|> seq) <* optional (skipChar '?' <|> skipChar '*' <|> skipChar '+')
205
+
206
+ /-- https://www.w3.org/TR/xml/#NT-contentspec -/
207
+ def contentspec : Parser Unit := do
208
+ skipString "EMPTY" <|> skipString "ANY" <|> Mixed <|> children
209
+
210
+ /-- https://www.w3.org/TR/xml/#NT-elementdecl -/
211
+ def elementDecl : Parser Unit := do
212
+ skipString "<!ELEMENT"
213
+ S *>
214
+ Name *>
215
+ contentspec *>
216
+ optional S *>
217
+ skipChar '>'
218
+
219
+ /-- https://www.w3.org/TR/xml/#NT-StringType -/
220
+ def StringType : Parser Unit :=
221
+ skipString "CDATA"
222
+
223
+ /-- https://www.w3.org/TR/xml/#NT-TokenizedType -/
224
+ def TokenizedType : Parser Unit :=
225
+ skipString "ID"
226
+ <|> skipString "IDREF"
227
+ <|> skipString "IDREFS"
228
+ <|> skipString "ENTITY"
229
+ <|> skipString "ENTITIES"
230
+ <|> skipString "NMTOKEN"
231
+ <|> skipString "NMTOKENS"
232
+
233
+ /-- https://www.w3.org/TR/xml/#NT-NotationType -/
234
+ def NotationType : Parser Unit := do
235
+ skipString "NOTATION"
236
+ S *>
237
+ skipChar '(' <*
238
+ optional S
239
+ Name *> many (optional S *> skipChar '|' *> optional S *> Name) *>
240
+ optional S *>
241
+ skipChar ')'
242
+
243
+ /-- https://www.w3.org/TR/xml/#NT-Nmtoken -/
244
+ def Nmtoken : Parser String := do
245
+ many1Chars NameChar
246
+
247
+ /-- https://www.w3.org/TR/xml/#NT-Enumeration -/
248
+ def Enumeration : Parser Unit := do
249
+ skipChar '('
250
+ optional S *>
251
+ Nmtoken *> many (optional S *> skipChar '|' *> optional S *> Nmtoken) *>
252
+ optional S *>
253
+ skipChar ')'
254
+
255
+ /-- https://www.w3.org/TR/xml/#NT-EnumeratedType -/
256
+ def EnumeratedType : Parser Unit :=
257
+ NotationType <|> Enumeration
258
+
259
+ /-- https://www.w3.org/TR/xml/#NT-AttType -/
260
+ def AttType : Parser Unit :=
261
+ StringType <|> TokenizedType <|> EnumeratedType
262
+
263
+ def predefinedEntityToChar : String β†’ Option LeanChar
264
+ | "lt" => some '<'
265
+ | "gt" => some '>'
266
+ | "amp" => some '&'
267
+ | "apos" => some '\''
268
+ | "quot" => some '"'
269
+ | _ => none
270
+
271
+ /-- https://www.w3.org/TR/xml/#NT-EntityRef -/
272
+ def EntityRef : Parser $ Option LeanChar := attempt $
273
+ skipChar '&' *> predefinedEntityToChar <$> Name <* skipChar ';'
274
+
275
+ @[inline]
276
+ def hexDigitToNat (c : LeanChar) : Nat :=
277
+ if '0' ≀ c ∧ c ≀ '9' then c.toNat - '0'.toNat
278
+ else if 'a' ≀ c ∧ c ≀ 'f' then c.toNat - 'a'.toNat + 10
279
+ else c.toNat - 'A'.toNat + 10
280
+
281
+ def digitsToNat (base : Nat) (digits : Array Nat) : Nat :=
282
+ digits.foldl (Ξ» r d => r * base + d) 0
283
+
284
+ /-- https://www.w3.org/TR/xml/#NT-CharRef -/
285
+ def CharRef : Parser LeanChar := do
286
+ skipString "&#"
287
+ let charCode ←
288
+ digitsToNat 10 <$> many1 (hexDigitToNat <$> digit)
289
+ <|> skipChar 'x' *> digitsToNat 16 <$> many1 (hexDigitToNat <$> hexDigit)
290
+ skipChar ';'
291
+ return Char.ofNat charCode
292
+
293
+ /-- https://www.w3.org/TR/xml/#NT-Reference -/
294
+ def Reference : Parser $ Option LeanChar :=
295
+ EntityRef <|> some <$> CharRef
296
+
297
+ /-- https://www.w3.org/TR/xml/#NT-AttValue -/
298
+ def AttValue : Parser String := do
299
+ let chars ←
300
+ (do
301
+ skipChar '"'
302
+ many (some <$> satisfy (Ξ» c => c β‰  '<' ∧ c β‰  '&' ∧ c β‰  '"') <|> Reference) <*
303
+ skipChar '"')
304
+ <|> (do
305
+ skipChar '\''
306
+ many (some <$> satisfy (Ξ» c => c β‰  '<' ∧ c β‰  '&' ∧ c β‰  '\'') <|> Reference) <*
307
+ skipChar '\'')
308
+ return chars.foldl (Ξ» s c => if let some c := c then s.push c else s) ""
309
+
310
+ /-- https://www.w3.org/TR/xml/#NT-DefaultDecl -/
311
+ def DefaultDecl : Parser Unit :=
312
+ skipString "#REQUIRED"
313
+ <|> skipString "#IMPLIED"
314
+ <|> optional (skipString "#FIXED" <* S) *> AttValue *> pure ()
315
+
316
+ /-- https://www.w3.org/TR/xml/#NT-AttDef -/
317
+ def AttDef : Parser Unit :=
318
+ S *> Name *> S *> AttType *> S *> DefaultDecl
319
+
320
+ /-- https://www.w3.org/TR/xml/#NT-AttlistDecl -/
321
+ def AttlistDecl : Parser Unit :=
322
+ skipString "<!ATTLIST" *> S *> Name *> many AttDef *> optional S *> skipChar '>'
323
+
324
+ /-- https://www.w3.org/TR/xml/#NT-PEReference -/
325
+ def PEReference : Parser Unit :=
326
+ skipChar '%' *> Name *> skipChar ';'
327
+
328
+ /-- https://www.w3.org/TR/xml/#NT-EntityValue -/
329
+ def EntityValue : Parser String := do
330
+ let chars ←
331
+ (do
332
+ skipChar '"'
333
+ many (some <$> satisfy (Ξ» c => c β‰  '%' ∧ c β‰  '&' ∧ c β‰  '"') <|> PEReference *> pure none <|> Reference) <*
334
+ skipChar '"')
335
+ <|> (do
336
+ skipChar '\''
337
+ many (some <$> satisfy (Ξ» c => c β‰  '%' ∧ c β‰  '&' ∧ c β‰  '\'') <|> PEReference *> pure none <|> Reference) <*
338
+ skipChar '\'')
339
+ return chars.foldl (Ξ» s c => if let some c := c then s.push c else s) ""
340
+
341
+
342
+ /-- https://www.w3.org/TR/xml/#NT-NDataDecl -/
343
+ def NDataDecl : Parser Unit :=
344
+ S *> skipString "NDATA" <* S <* Name
345
+
346
+ /-- https://www.w3.org/TR/xml/#NT-EntityDef -/
347
+ def EntityDef : Parser Unit :=
348
+ EntityValue *> pure () <|> (ExternalID <* optional NDataDecl)
349
+
350
+ /-- https://www.w3.org/TR/xml/#NT-GEDecl -/
351
+ def GEDecl : Parser Unit :=
352
+ skipString "<!ENTITY" *> S *> Name *> S *> EntityDef *> optional S *> skipChar '>'
353
+
354
+ /-- https://www.w3.org/TR/xml/#NT-PEDef -/
355
+ def PEDef : Parser Unit :=
356
+ EntityValue *> pure () <|> ExternalID
357
+
358
+ /-- https://www.w3.org/TR/xml/#NT-PEDecl -/
359
+ def PEDecl : Parser Unit :=
360
+ skipString "<!ENTITY" *> S *> skipChar '%' *> S *> Name *> PEDef *> optional S *> skipChar '>'
361
+
362
+ /-- https://www.w3.org/TR/xml/#NT-EntityDecl -/
363
+ def EntityDecl : Parser Unit :=
364
+ GEDecl <|> PEDecl
365
+
366
+ /-- https://www.w3.org/TR/xml/#NT-PublicID -/
367
+ def PublicID : Parser Unit :=
368
+ skipString "PUBLIC" <* S <* PubidLiteral
369
+
370
+ /-- https://www.w3.org/TR/xml/#NT-NotationDecl -/
371
+ def NotationDecl : Parser Unit :=
372
+ skipString "<!NOTATION" *> S *> Name *> (ExternalID <|> PublicID) *> optional S *> skipChar '>'
373
+
374
+ /-- https://www.w3.org/TR/xml/#NT-markupdecl -/
375
+ def markupDecl : Parser Unit :=
376
+ elementDecl <|> AttlistDecl <|> EntityDecl <|> NotationDecl <|> PI <|> (Comment *> pure ())
377
+
378
+ /-- https://www.w3.org/TR/xml/#NT-DeclSep -/
379
+ def DeclSep : Parser Unit :=
380
+ PEReference <|> S *> pure ()
381
+
382
+ /-- https://www.w3.org/TR/xml/#NT-intSubset -/
383
+ def intSubset : Parser Unit :=
384
+ many (markupDecl <|> DeclSep) *> pure ()
385
+
386
+ /-- https://www.w3.org/TR/xml/#NT-doctypedecl -/
387
+ def doctypedecl : Parser Unit := do
388
+ skipString "<!DOCTYPE"
389
+ S *>
390
+ Name *>
391
+ optional (S *> ExternalID) *> pure ()
392
+ <* optional S
393
+ optional (skipChar '[' *> intSubset <* skipChar ']' <* optional S) *>
394
+ skipChar '>'
395
+
396
+ /-- https://www.w3.org/TR/xml/#NT-prolog -/
397
+ def prolog : Parser Unit :=
398
+ optional XMLdecl *>
399
+ many Misc *>
400
+ optional (doctypedecl <* many Misc) *> pure ()
401
+
402
+ /-- https://www.w3.org/TR/xml/#NT-Attribute -/
403
+ def Attribute : Parser (String Γ— String) := do
404
+ let name ← Name
405
+ Eq
406
+ let value ← AttValue
407
+ return (name, value)
408
+
409
+ protected def elementPrefix : Parser (Array Content β†’ Element) := do
410
+ skipChar '<'
411
+ let name ← Name
412
+ let attributes ← many (attempt <| S *> Attribute)
413
+ optional S *> pure ()
414
+ return Element.Element name (RBMap.fromList attributes.toList compare)
415
+
416
+ /-- https://www.w3.org/TR/xml/#NT-EmptyElemTag -/
417
+ def EmptyElemTag (elem : Array Content β†’ Element) : Parser Element := do
418
+ skipString "/>" *> pure (elem #[])
419
+
420
+ /-- https://www.w3.org/TR/xml/#NT-STag -/
421
+ def STag (elem : Array Content β†’ Element) : Parser (Array Content β†’ Element) := do
422
+ skipChar '>' *> pure elem
423
+
424
+ /-- https://www.w3.org/TR/xml/#NT-ETag -/
425
+ def ETag : Parser Unit :=
426
+ skipString "</" *> Name *> optional S *> skipChar '>'
427
+
428
+ /-- https://www.w3.org/TR/xml/#NT-CDStart -/
429
+ def CDStart : Parser Unit :=
430
+ skipString "<![CDATA["
431
+
432
+ /-- https://www.w3.org/TR/xml/#NT-CDEnd -/
433
+ def CDEnd : Parser Unit :=
434
+ skipString "]]>"
435
+
436
+ /-- https://www.w3.org/TR/xml/#NT-CData -/
437
+ def CData : Parser String :=
438
+ manyChars (notFollowedBy (skipString "]]>") *> any)
439
+
440
+ /-- https://www.w3.org/TR/xml/#NT-CDSect -/
441
+ def CDSect : Parser String :=
442
+ CDStart *> CData <* CDEnd
443
+
444
+ /-- https://www.w3.org/TR/xml/#NT-CharData -/
445
+ def CharData : Parser String :=
446
+ notFollowedBy (skipString "]]>") *> manyChars (satisfy Ξ» c => c β‰  '<' ∧ c β‰  '&')
447
+
448
+ mutual
449
+ /-- https://www.w3.org/TR/xml/#NT-content -/
450
+ partial def content : Parser (Array Content) := do
451
+ let x ← optional (Content.Character <$> CharData)
452
+ let xs ← many do
453
+ let y ←
454
+ attempt (some <$> Content.Element <$> element)
455
+ <|> (do let c ← Reference; pure <| c.map (Content.Character ∘ Char.toString))
456
+ <|> some <$> Content.Character <$> CDSect
457
+ <|> PI *> pure none
458
+ <|> some <$> Content.Comment <$> Comment
459
+
460
+ let z ← optional (Content.Character <$> CharData)
461
+ pure #[y, z]
462
+ let xs := #[x] ++ xs.flatMap id |>.filterMap id
463
+ let mut res := #[]
464
+ for x in xs do
465
+ if res.size > 0 then
466
+ match res.back!, x with
467
+ | Content.Character x, Content.Character y => res := res.set! (res.size - 1) (Content.Character $ x ++ y)
468
+ | _, x => res := res.push x
469
+ else res := res.push x
470
+ return res
471
+
472
+ /-- https://www.w3.org/TR/xml/#NT-element -/
473
+ partial def element : Parser Element := do
474
+ let elem ← Parser.elementPrefix
475
+ EmptyElemTag elem <|> STag elem <*> content <* ETag
476
+
477
+ end
478
+
479
+ /-- https://www.w3.org/TR/xml/#NT-document -/
480
+ def document : Parser Element := prolog *> element <* many Misc <* eof
481
+
482
+ end Parser
483
+
484
+ def parse (s : String) : Except String Element :=
485
+ Parser.run Xml.Parser.document s
486
+
487
+ end Xml
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/DocString/Add.lean ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: David Thrane Christiansen
5
+ -/
6
+
7
+ prelude
8
+ import Lean.Environment
9
+ import Lean.Exception
10
+ import Lean.Log
11
+ import Lean.DocString.Extension
12
+ import Lean.DocString.Links
13
+
14
+ set_option linter.missingDocs true
15
+
16
+ namespace Lean
17
+
18
+ /--
19
+ Validates all links to the Lean reference manual in `docstring`.
20
+
21
+ This is intended to be used before saving a docstring that is later subject to rewriting with
22
+ `rewriteManualLinks`.
23
+ -/
24
+ def validateDocComment
25
+ [Monad m] [MonadLog m] [AddMessageContext m] [MonadOptions m] [MonadLiftT IO m]
26
+ (docstring : TSyntax `Lean.Parser.Command.docComment) :
27
+ m Unit := do
28
+ let str := docstring.getDocString
29
+ let pos? := docstring.raw[1].getHeadInfo? >>= (Β·.getPos?)
30
+
31
+ let (errs, out) ← (rewriteManualLinksCore str : IO _)
32
+
33
+ for (⟨start, stop⟩, err) in errs do
34
+ -- Report errors at their actual location if possible
35
+ if let some pos := pos? then
36
+ let urlStx : Syntax := .atom (.synthetic (pos + start) (pos + stop)) (str.extract start stop)
37
+ logErrorAt urlStx err
38
+ else
39
+ logError err
40
+
41
+ /--
42
+ Adds a docstring to the environment, validating documentation links.
43
+ -/
44
+ def addDocString
45
+ [Monad m] [MonadError m] [MonadEnv m] [MonadLog m] [AddMessageContext m] [MonadOptions m] [MonadLiftT IO m]
46
+ (declName : Name) (docComment : TSyntax `Lean.Parser.Command.docComment) : m Unit := do
47
+ unless (← getEnv).getModuleIdxFor? declName |>.isNone do
48
+ throwError s!"invalid doc string, declaration '{declName}' is in an imported module"
49
+ validateDocComment docComment
50
+ let docString : String ← getDocStringText docComment
51
+ modifyEnv fun env => docStringExt.insert env declName docString.removeLeadingSpaces
52
+
53
+ /--
54
+ Adds a docstring to the environment, validating documentation links.
55
+ -/
56
+ def addDocString'
57
+ [Monad m] [MonadError m] [MonadEnv m] [MonadLog m] [AddMessageContext m] [MonadOptions m] [MonadLiftT IO m]
58
+ (declName : Name) (docString? : Option (TSyntax `Lean.Parser.Command.docComment)) : m Unit :=
59
+ match docString? with
60
+ | some docString => addDocString declName docString
61
+ | none => return ()
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/DocString/Extension.lean ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.DeclarationRange
8
+ import Lean.DocString.Links
9
+ import Lean.MonadEnv
10
+ import Init.Data.String.Extra
11
+
12
+ -- This module contains the underlying data for docstrings, with as few imports as possible, so that
13
+ -- docstrings can be saved in as much of the compiler as possible.
14
+ -- The module `Lean.DocString` contains the query interface, which needs to look at additional data
15
+ -- to construct user-visible docstrings.
16
+
17
+ namespace Lean
18
+
19
+ private builtin_initialize builtinDocStrings : IO.Ref (NameMap String) ← IO.mkRef {}
20
+ builtin_initialize docStringExt : MapDeclarationExtension String ← mkMapDeclarationExtension
21
+
22
+ /--
23
+ Adds a builtin docstring to the compiler.
24
+
25
+ Links to the Lean manual aren't validated.
26
+ -/
27
+ -- See the test `lean/run/docstringRewrites.lean` for the validation of builtin docstring links
28
+ def addBuiltinDocString (declName : Name) (docString : String) : IO Unit := do
29
+ builtinDocStrings.modify (Β·.insert declName docString.removeLeadingSpaces)
30
+
31
+ def addDocStringCore [Monad m] [MonadError m] [MonadEnv m] (declName : Name) (docString : String) : m Unit := do
32
+ unless (← getEnv).getModuleIdxFor? declName |>.isNone do
33
+ throwError s!"invalid doc string, declaration '{declName}' is in an imported module"
34
+ modifyEnv fun env => docStringExt.insert env declName docString.removeLeadingSpaces
35
+
36
+ def addDocStringCore' [Monad m] [MonadError m] [MonadEnv m] (declName : Name) (docString? : Option String) : m Unit :=
37
+ match docString? with
38
+ | some docString => addDocStringCore declName docString
39
+ | none => return ()
40
+
41
+ /--
42
+ Finds a docstring without performing any alias resolution or enrichment with extra metadata.
43
+
44
+ Docstrings to be shown to a user should be looked up with `Lean.findDocString?` instead.
45
+ -/
46
+ def findSimpleDocString? (env : Environment) (declName : Name) (includeBuiltin := true) : IO (Option String) :=
47
+ if let some docStr := docStringExt.find? env declName then
48
+ return some docStr
49
+ else if includeBuiltin then
50
+ return (← builtinDocStrings.get).find? declName
51
+ else
52
+ return none
53
+
54
+ structure ModuleDoc where
55
+ doc : String
56
+ declarationRange : DeclarationRange
57
+
58
+ private builtin_initialize moduleDocExt : SimplePersistentEnvExtension ModuleDoc (PersistentArray ModuleDoc) ← registerSimplePersistentEnvExtension {
59
+ addImportedFn := fun _ => {}
60
+ addEntryFn := fun s e => s.push e
61
+ exportEntriesFnEx? := some fun _ _ es level =>
62
+ if level < .server then
63
+ #[]
64
+ else
65
+ es.toArray
66
+ }
67
+
68
+ def addMainModuleDoc (env : Environment) (doc : ModuleDoc) : Environment :=
69
+ moduleDocExt.addEntry env doc
70
+
71
+ def getMainModuleDoc (env : Environment) : PersistentArray ModuleDoc :=
72
+ moduleDocExt.getState env
73
+
74
+ def getModuleDoc? (env : Environment) (moduleName : Name) : Option (Array ModuleDoc) :=
75
+ env.getModuleIdx? moduleName |>.map fun modIdx =>
76
+ moduleDocExt.getModuleEntries (level := .server) env modIdx
77
+
78
+ def getDocStringText [Monad m] [MonadError m] (stx : TSyntax `Lean.Parser.Command.docComment) : m String :=
79
+ match stx.raw[1] with
80
+ | Syntax.atom _ val => return val.extract 0 (val.endPos - ⟨2⟩)
81
+ | _ => throwErrorAt stx "unexpected doc string{indentD stx.raw[1]}"
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/DocString/Links.lean ADDED
@@ -0,0 +1,171 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: David Thrane Christiansen
5
+ -/
6
+
7
+ prelude
8
+ import Lean.Syntax
9
+
10
+ set_option linter.missingDocs true
11
+
12
+ namespace Lean
13
+
14
+ @[extern "lean_manual_get_root"]
15
+ private opaque getManualRoot : Unit β†’ String
16
+
17
+ private def fallbackManualRoot := "https://lean-lang.org/doc/reference/latest/"
18
+
19
+ /--
20
+ Computes the root of the Lean reference manual that should be used for targets.
21
+
22
+ If the environment variable `LEAN_MANUAL_ROOT` is set, it is used as the root. If not, but a manual
23
+ root is pre-configured for the current Lean executable (typically true for releases), then it is
24
+ used. If neither are true, then `https://lean-lang.org/doc/reference/latest/` is used.
25
+ -/
26
+ builtin_initialize manualRoot : String ←
27
+ let r ←
28
+ if let some root := (← IO.getEnv "LEAN_MANUAL_ROOT") then
29
+ pure root
30
+ else
31
+ let root := getManualRoot ()
32
+ if root.isEmpty then
33
+ pure fallbackManualRoot
34
+ else
35
+ pure root
36
+ return if r.endsWith "/" then r else r ++ "/"
37
+
38
+ /--
39
+ The manual domain for error explanations.
40
+
41
+ We expose this because it is used to populate the URL of the error message description widget.
42
+ -/
43
+ def errorExplanationManualDomain :=
44
+ "Manual.errorExplanation"
45
+
46
+ -- TODO: we may wish to make this more general for domains that require additional arguments
47
+ /-- Maps `lean-manual` URL paths to their corresponding manual domains. -/
48
+ private def domainMap : Std.HashMap String String :=
49
+ Std.HashMap.ofList [
50
+ ("section", "Verso.Genre.Manual.section"),
51
+ ("errorExplanation", errorExplanationManualDomain)
52
+ ]
53
+
54
+ /--
55
+ Rewrites links from the internal Lean manual syntax to the correct URL. This rewriting is an
56
+ overapproximation: any parentheses containing the internal syntax of a Lean manual URL is rewritten.
57
+
58
+ The internal syntax is the URL scheme `lean-manual` followed by the path `/KIND/MORE...`, where
59
+ `KIND` is a kind of content being linked to. Presently, the only valid kind is `section`, and it
60
+ requires that the remainder of the path consists of one element, which is a section or part identifier.
61
+
62
+ The correct URL is based on a manual root URL, which is determined by the `LEAN_MANUAL_ROOT`
63
+ environment variable. If this environment variable is not set, a manual root provided when Lean was
64
+ built is used (typically this is the version corresponding to the current release). If no such root
65
+ is available, the latest version of the manual is used.
66
+ -/
67
+ def rewriteManualLinksCore (s : String) : BaseIO (Array (String.Range Γ— String) Γ— String) := do
68
+ let scheme := "lean-manual://"
69
+ let mut out := ""
70
+ let mut errors := #[]
71
+ let mut iter := s.iter
72
+ while h : iter.hasNext do
73
+ let c := iter.curr' h
74
+ iter := iter.next' h
75
+
76
+ if !lookingAt scheme iter.prev then
77
+ out := out.push c
78
+ continue
79
+
80
+ let start := iter.prev.forward scheme.length
81
+ let mut iter' := start
82
+ while h' : iter'.hasNext do
83
+ let c' := iter'.curr' h'
84
+ iter' := iter'.next' h'
85
+ if urlChar c' && !iter'.atEnd then
86
+ continue
87
+ match rw (start.extract iter'.prev) with
88
+ | .error err =>
89
+ errors := errors.push (⟨iter.prev.i, iter'.prev.i⟩, err)
90
+ out := out.push c
91
+ break
92
+ | .ok path =>
93
+ out := out ++ manualRoot ++ path
94
+ out := out.push c'
95
+ iter := iter'
96
+ break
97
+
98
+ pure (errors, out)
99
+
100
+ where
101
+ /--
102
+ Returns `true` if the character is one of those allowed in RFC 3986 sections 2.2 and 2.3. other
103
+ than '(' or')'.
104
+ -/
105
+ urlChar (c : Char) : Bool :=
106
+ -- unreserved
107
+ c.isAlphanum || c == '-' || c == '.' || c == '_' || c == '~' ||
108
+ -- gen-delims
109
+ c == ':' || c == '/' || c == '?' || c == '#' || c == '[' || c == ']' || c == '@' ||
110
+ -- sub-delims
111
+ -- ( and ) are excluded due to Markdown's link syntax
112
+ c == '!' || c == '$' || c == '&' || c == '\'' || /- c == '(' || c == ')' || -/ c == '*' ||
113
+ c == '+' || c == ',' || c == ';' || c == '='
114
+
115
+ /--
116
+ Returns `true` if `goal` is a prefix of the string at the position pointed to by `iter`.
117
+ -/
118
+ lookingAt (goal : String) (iter : String.Iterator) : Bool :=
119
+ iter.s.substrEq iter.i goal 0 goal.endPos.byteIdx
120
+
121
+ rw (path : String) : Except String String := do
122
+ match path.splitOn "/" with
123
+ | [] | [""] =>
124
+ throw "Missing documentation type"
125
+ | kind :: args =>
126
+ if let some domain := domainMap.get? kind then
127
+ if let [s] := args then
128
+ if s.isEmpty then
129
+ throw s!"Empty {kind} ID"
130
+ return s!"find/?domain={domain}&name={s}"
131
+ else
132
+ throw s!"Expected one item after `{kind}`, but got {args}"
133
+ else
134
+ let acceptableKinds := ", ".intercalate <| domainMap.toList.map fun (k, _) => s!"`{k}`"
135
+ throw s!"Unknown documentation type `{kind}`. Expected one of the following: {acceptableKinds}"
136
+
137
+
138
+ /--
139
+ Rewrites Lean reference manual links in `docstring` to point at the reference manual.
140
+
141
+ This assumes that all such links have already been validated by `validateDocComment`.
142
+ -/
143
+ def rewriteManualLinks (docString : String) : BaseIO String := do
144
+ let (errs, str) ← rewriteManualLinksCore docString
145
+ if !errs.isEmpty then
146
+ let errReport :=
147
+ r#"**❌ Syntax Errors in Lean Language Reference Links**
148
+
149
+ The `lean-manual` URL scheme is used to link to the version of the Lean reference manual that
150
+ corresponds to this version of Lean. Errors occurred while processing the links in this documentation
151
+ comment:
152
+ "# ++
153
+ String.join (errs.toList.map (fun (⟨s, e⟩, msg) => s!" * ```{docString.extract s e}```: {msg}\n\n"))
154
+ return str ++ "\n\n" ++ errReport
155
+ return str
156
+
157
+
158
+ /--
159
+ Validates all links to the Lean reference manual in `docstring`, printing an error message if any
160
+ are invalid. Returns `true` if all links are valid.
161
+
162
+ This is intended to be used before saving a docstring that is later subject to rewriting with
163
+ `rewriteManualLinks`, in contexts where the imports needed to produce better error messages in
164
+ `validateDocComment` are not yet available.
165
+ -/
166
+ def validateBuiltinDocString (docString : String) : IO Unit := do
167
+ let (errs, _) ← rewriteManualLinksCore docString
168
+ if !errs.isEmpty then
169
+ throw <| IO.userError <|
170
+ s!"Errors in builtin documentation comment:\n" ++
171
+ String.join (errs.toList.map fun (⟨s, e⟩, msg) => s!" * {repr <| docString.extract s e}:\n {msg}\n")
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/App.lean ADDED
@@ -0,0 +1,1854 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2019 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Util.FindMVar
8
+ import Lean.Util.CollectFVars
9
+ import Lean.Parser.Term
10
+ import Lean.Meta.KAbstract
11
+ import Lean.Meta.Tactic.ElimInfo
12
+ import Lean.Elab.Term
13
+ import Lean.Elab.Binders
14
+ import Lean.Elab.SyntheticMVars
15
+ import Lean.Elab.Arg
16
+ import Lean.Elab.RecAppSyntax
17
+
18
+ namespace Lean.Elab.Term
19
+ open Meta
20
+
21
+ /--
22
+ Instructs the elaborator to elaborate applications of the given declaration without an expected
23
+ type. This may prevent the elaborator from incorrectly inferring implicit arguments.
24
+ -/
25
+ @[builtin_doc]
26
+ builtin_initialize elabWithoutExpectedTypeAttr : TagAttribute ←
27
+ registerTagAttribute `elab_without_expected_type "mark that applications of the given declaration should be elaborated without the expected type"
28
+
29
+ def hasElabWithoutExpectedType (env : Environment) (declName : Name) : Bool :=
30
+ elabWithoutExpectedTypeAttr.hasTag env declName
31
+
32
+ instance : ToString Arg where
33
+ toString
34
+ | .stx val => toString val
35
+ | .expr val => toString val
36
+
37
+ instance : ToString NamedArg where
38
+ toString s := "(" ++ toString s.name ++ " := " ++ toString s.val ++ ")"
39
+
40
+ def throwInvalidNamedArg (namedArg : NamedArg) (fn? : Option Name) : TermElabM Ξ± :=
41
+ withRef namedArg.ref <| match fn? with
42
+ | some fn => throwError "invalid argument name '{namedArg.name}' for function '{fn}'"
43
+ | none => throwError "invalid argument name '{namedArg.name}' for function"
44
+
45
+ private def ensureArgType (f : Expr) (arg : Expr) (expectedType : Expr) : TermElabM Expr := do
46
+ try
47
+ ensureHasType expectedType arg none f
48
+ catch
49
+ | ex@(.error ..) =>
50
+ if (← read).errToSorry then
51
+ exceptionToSorry ex expectedType
52
+ else
53
+ throw ex
54
+ | ex => throw ex
55
+
56
+ private def mkProjAndCheck (structName : Name) (idx : Nat) (e : Expr) : MetaM Expr := do
57
+ let r := mkProj structName idx e
58
+ let eType ← inferType e
59
+ if (← isProp eType) then
60
+ let rType ← inferType r
61
+ if !(← isProp rType) then
62
+ throwError "Invalid projection: Cannot project a value of non-propositional type{indentExpr rType}\
63
+ \nfrom the expression{indentExpr e}\nwhich has propositional type{indentExpr eType}"
64
+ return r
65
+
66
+ def synthesizeAppInstMVars (instMVars : Array MVarId) (app : Expr) : TermElabM Unit :=
67
+ for mvarId in instMVars do
68
+ unless (← synthesizeInstMVarCore mvarId) do
69
+ registerSyntheticMVarWithCurrRef mvarId (.typeClass none)
70
+ registerMVarErrorImplicitArgInfo mvarId (← getRef) app
71
+
72
+ /-- Return `some namedArg` if `namedArgs` contains an entry for `binderName`. -/
73
+ private def findBinderName? (namedArgs : List NamedArg) (binderName : Name) : Option NamedArg :=
74
+ namedArgs.find? fun namedArg => namedArg.name == binderName
75
+
76
+ /-- Erase entry for `binderName` from `namedArgs`. -/
77
+ def eraseNamedArg (namedArgs : List NamedArg) (binderName : Name) : List NamedArg :=
78
+ namedArgs.filter (Β·.name != binderName)
79
+
80
+ /-- Return true if the given type contains `OptParam` or `AutoParams` -/
81
+ private def hasOptAutoParams (type : Expr) : MetaM Bool := do
82
+ forallTelescopeReducing type fun xs _ =>
83
+ xs.anyM fun x => do
84
+ let xType ← inferType x
85
+ return xType.getOptParamDefault?.isSome || xType.getAutoParamTactic?.isSome
86
+
87
+
88
+ /-! # Default application elaborator -/
89
+ namespace ElabAppArgs
90
+
91
+ structure Context where
92
+ /--
93
+ `true` if `..` was used
94
+ -/
95
+ ellipsis : Bool --
96
+ /--
97
+ `true` if `@` modifier was used
98
+ -/
99
+ explicit : Bool
100
+ /--
101
+ If the result type of an application is the `outParam` of some local instance, then special support may be needed
102
+ because type class resolution interacts poorly with coercions in this kind of situation.
103
+ This flag enables the special support.
104
+
105
+ The idea is quite simple, if the result type is the `outParam` of some local instance, we simply
106
+ execute `synthesizeSyntheticMVarsUsingDefault`. We added this feature to make sure examples as follows
107
+ are correctly elaborated.
108
+ ```lean
109
+ class GetElem (Cont : Type u) (Idx : Type v) (Elem : outParam (Type w)) where
110
+ getElem (xs : Cont) (i : Idx) : Elem
111
+
112
+ export GetElem (getElem)
113
+
114
+ instance : GetElem (Array Ξ±) Nat Ξ± where
115
+ getElem xs i := xs.get ⟨i, sorry⟩
116
+
117
+ opaque f : Option Bool β†’ Bool
118
+ opaque g : Bool β†’ Bool
119
+
120
+ def bad (xs : Array Bool) : Bool :=
121
+ let x := getElem xs 0
122
+ f x && g x
123
+ ```
124
+ Without the special support, Lean fails at `g x` saying `x` has type `Option Bool` but is expected to have type `Bool`.
125
+ From the user's point of view this is a bug, since `let x := getElem xs 0` clearly constrains `x` to be `Bool`, but
126
+ we only obtain this information after we apply the `OfNat` default instance for `0`.
127
+
128
+ Before converging to this solution, we have tried to create a "coercion placeholder" when `resultIsOutParamSupport = true`,
129
+ but it did not work well in practice. For example, it failed in the example above.
130
+ -/
131
+ resultIsOutParamSupport : Bool
132
+
133
+ /-- Auxiliary structure for elaborating the application `f args namedArgs`. -/
134
+ structure State where
135
+ f : Expr
136
+ fType : Expr
137
+ /-- Remaining regular arguments. -/
138
+ args : List Arg
139
+ /-- remaining named arguments to be processed. -/
140
+ namedArgs : List NamedArg
141
+ expectedType? : Option Expr
142
+ /--
143
+ When named arguments are provided and explicit arguments occurring before them are missing,
144
+ the elaborator eta-expands the declaration. For example,
145
+ ```
146
+ def f (x y : Nat) := x + y
147
+ #check f (y := 5)
148
+ -- fun x => f x 5
149
+ ```
150
+ `etaArgs` stores the fresh free variables for implementing the eta-expansion.
151
+ When `..` is used, eta-expansion is disabled, and missing arguments are treated as `_`.
152
+ -/
153
+ etaArgs : Array Expr := #[]
154
+ /-- Metavariables that we need to set the error context using the application being built. -/
155
+ toSetErrorCtx : Array MVarId := #[]
156
+ /-- Metavariables for the instance implicit arguments that have already been processed. -/
157
+ instMVars : Array MVarId := #[]
158
+ /--
159
+ The following field is used to implement the `propagateExpectedType` heuristic.
160
+ It is set to `true` true when `expectedType` still has to be propagated.
161
+ -/
162
+ propagateExpected : Bool
163
+ /--
164
+ If the result type may be the `outParam` of some local instance.
165
+ See comment at `Context.resultIsOutParamSupport`
166
+ -/
167
+ resultTypeOutParam? : Option MVarId := none
168
+
169
+ abbrev M := ReaderT Context (StateRefT State TermElabM)
170
+
171
+ /-- Add the given metavariable to the collection of metavariables associated with instance-implicit arguments. -/
172
+ private def addInstMVar (mvarId : MVarId) : M Unit :=
173
+ modify fun s => { s with instMVars := s.instMVars.push mvarId }
174
+
175
+ /--
176
+ Try to synthesize metavariables are `instMVars` using type class resolution.
177
+ The ones that cannot be synthesized yet stay in the `instMVars` list.
178
+ Remark: we use this method
179
+ - before trying to apply coercions to function,
180
+ - before unifying the expected type.
181
+ -/
182
+ def trySynthesizeAppInstMVars : M Unit := do
183
+ let instMVars ← (← get).instMVars.filterM fun instMVar => do
184
+ unless (← instantiateMVars (← inferType (.mvar instMVar))).isMVar do try
185
+ if (← synthesizeInstMVarCore instMVar) then
186
+ return false
187
+ catch _ => pure ()
188
+ return true
189
+ modify ({ Β· with instMVars })
190
+
191
+ /--
192
+ Try to synthesize metavariables are `instMVars` using type class resolution.
193
+ The ones that cannot be synthesized yet are registered.
194
+ -/
195
+ def synthesizeAppInstMVars : M Unit := do
196
+ Term.synthesizeAppInstMVars (← get).instMVars (← get).f
197
+ modify ({ Β· with instMVars := #[] })
198
+
199
+ /-- fType may become a forallE after we synthesize pending metavariables. -/
200
+ private def synthesizePendingAndNormalizeFunType : M Unit := do
201
+ trySynthesizeAppInstMVars
202
+ synthesizeSyntheticMVars
203
+ let s ← get
204
+ let fType ← whnfForall s.fType
205
+ if fType.isForall then
206
+ modify fun s => { s with fType }
207
+ else
208
+ if let some f ← coerceToFunction? s.f then
209
+ let fType ← inferType f
210
+ modify fun s => { s with f, fType }
211
+ else
212
+ for namedArg in s.namedArgs do
213
+ let f := s.f.getAppFn
214
+ if f.isConst then
215
+ throwInvalidNamedArg namedArg f.constName!
216
+ else
217
+ throwInvalidNamedArg namedArg none
218
+ -- Help users see if this is actually due to an indentation mismatch/other parsing mishaps:
219
+ let extra := if let some (arg : Arg) := s.args[0]? then
220
+ .note m!"Expected a function because this term is being applied to the argument\
221
+ {indentD <| toMessageData arg}"
222
+ else .nil
223
+ throwError "Function expected at{indentExpr s.f}\nbut this term has type{indentExpr fType}{extra}"
224
+
225
+ /-- Normalize and return the function type. -/
226
+ private def normalizeFunType : M Expr := do
227
+ let s ← get
228
+ let fType ← whnfForall s.fType
229
+ modify fun s => { s with fType }
230
+ return fType
231
+
232
+ /-- Return the binder name at `fType`. This method assumes `fType` is a function type. -/
233
+ private def getBindingName : M Name := return (← get).fType.bindingName!
234
+
235
+ /-- Return the next argument expected type. This method assumes `fType` is a function type. -/
236
+ private def getArgExpectedType : M Expr := return (← get).fType.bindingDomain!
237
+
238
+ /-- Remove named argument with name `binderName` from `namedArgs`. -/
239
+ def eraseNamedArg (binderName : Name) : M Unit :=
240
+ modify fun s => { s with namedArgs := Term.eraseNamedArg s.namedArgs binderName }
241
+
242
+ /--
243
+ Add a new argument to the result. That is, `f := f arg`, update `fType`.
244
+ This method assumes `fType` is a function type. -/
245
+ private def addNewArg (argName : Name) (arg : Expr) : M Unit := do
246
+ modify fun s => { s with f := mkApp s.f arg, fType := s.fType.bindingBody!.instantiate1 arg }
247
+ if arg.isMVar then
248
+ registerMVarArgName arg.mvarId! argName
249
+
250
+ /--
251
+ Elaborate the given `Arg` and add it to the result. See `addNewArg`.
252
+ Recall that, `Arg` may be wrapping an already elaborated `Expr`. -/
253
+ private def elabAndAddNewArg (argName : Name) (arg : Arg) : M Unit := do
254
+ let s ← get
255
+ let expectedType := (← getArgExpectedType).consumeTypeAnnotations
256
+ match arg with
257
+ | Arg.expr val =>
258
+ let arg ← ensureArgType s.f val expectedType
259
+ addNewArg argName arg
260
+ | Arg.stx stx =>
261
+ let val ← elabTerm stx expectedType
262
+ let arg ← withRef stx <| ensureArgType s.f val expectedType
263
+ addNewArg argName arg
264
+
265
+ /-- Return true if `fType` contains `OptParam` or `AutoParams` -/
266
+ private def fTypeHasOptAutoParams : M Bool := do
267
+ hasOptAutoParams (← get).fType
268
+
269
+ /--
270
+ Auxiliary function for retrieving the resulting type of a function application.
271
+ See `propagateExpectedType`.
272
+ Remark: `(explicit : Bool) == true` when `@` modifier is used. -/
273
+ private partial def getForallBody (explicit : Bool) : Nat β†’ List NamedArg β†’ Expr β†’ Option Expr
274
+ | i, namedArgs, type@(.forallE n d b bi) =>
275
+ match findBinderName? namedArgs n with
276
+ | some _ => getForallBody explicit i (Term.eraseNamedArg namedArgs n) b
277
+ | none =>
278
+ if !explicit && !bi.isExplicit then
279
+ getForallBody explicit i namedArgs b
280
+ else if i > 0 then
281
+ getForallBody explicit (i-1) namedArgs b
282
+ else if d.isAutoParam || d.isOptParam then
283
+ getForallBody explicit i namedArgs b
284
+ else
285
+ some type
286
+ | 0, [], type => some type
287
+ | _, _, _ => none
288
+
289
+ private def shouldPropagateExpectedTypeFor (nextArg : Arg) : Bool :=
290
+ match nextArg with
291
+ | .expr _ => false -- it has already been elaborated
292
+ | .stx stx =>
293
+ -- TODO: make this configurable?
294
+ stx.getKind != ``Lean.Parser.Term.hole &&
295
+ stx.getKind != ``Lean.Parser.Term.syntheticHole &&
296
+ stx.getKind != ``Lean.Parser.Term.byTactic
297
+
298
+ /--
299
+ Auxiliary method for propagating the expected type. We call it as soon as we find the first explicit
300
+ argument. The goal is to propagate the expected type in applications of functions such as
301
+ ```lean
302
+ Add.add {Ξ± : Type u} : Ξ± β†’ Ξ± β†’ Ξ±
303
+ List.cons {Ξ± : Type u} : Ξ± β†’ List Ξ± β†’ List Ξ±
304
+ ```
305
+ This is particularly useful when there applicable coercions. For example,
306
+ assume we have a coercion from `Nat` to `Int`, and we have
307
+ `(x : Nat)` and the expected type is `List Int`. Then, if we don't use this function,
308
+ the elaborator will fail to elaborate
309
+ ```
310
+ List.cons x []
311
+ ```
312
+ First, the elaborator creates a new metavariable `?Ξ±` for the implicit argument `{Ξ± : Type u}`.
313
+ Then, when it processes `x`, it assigns `?Ξ± := Nat`, and then obtains the
314
+ resultant type `List Nat` which is **not** definitionally equal to `List Int`.
315
+ We solve the problem by executing this method before we elaborate the first explicit argument (`x` in this example).
316
+ This method infers that the resultant type is `List ?Ξ±` and unifies it with `List Int`.
317
+ Then, when we elaborate `x`, the elaborate realizes the coercion from `Nat` to `Int` must be used, and the
318
+ term
319
+ ```
320
+ @List.cons Int (coe x) (@List.nil Int)
321
+ ```
322
+ is produced.
323
+
324
+ The method will do nothing if
325
+ 1- The resultant type depends on the remaining arguments (i.e., `!eTypeBody.hasLooseBVars`).
326
+ 2- The resultant type contains optional/auto params.
327
+
328
+ We have considered adding the following extra conditions
329
+ a) The resultant type does not contain any type metavariable.
330
+ b) The resultant type contains a nontype metavariable.
331
+
332
+ These two conditions would restrict the method to simple functions that are "morally" in
333
+ the Hindley&Milner fragment.
334
+ If users need to disable expected type propagation, we can add an attribute `[elab_without_expected_type]`.
335
+ -/
336
+ private def propagateExpectedType (arg : Arg) : M Unit := do
337
+ if shouldPropagateExpectedTypeFor arg then
338
+ let s ← get
339
+ -- TODO: handle s.etaArgs.size > 0
340
+ unless !s.etaArgs.isEmpty || !s.propagateExpected do
341
+ match s.expectedType? with
342
+ | none => pure ()
343
+ | some expectedType =>
344
+ /- We don't propagate `Prop` because we often use `Prop` as a more general "Bool" (e.g., `if-then-else`).
345
+ If we propagate `expectedType == Prop` in the following examples, the elaborator would fail
346
+ ```
347
+ def f1 (s : Nat Γ— Bool) : Bool := if s.2 then false else true
348
+
349
+ def f2 (s : List Bool) : Bool := if s.head! then false else true
350
+
351
+ def f3 (s : List Bool) : Bool := if List.head! (s.map not) then false else true
352
+ ```
353
+ They would all fail for the same reason. So, let's focus on the first one.
354
+ We would elaborate `s.2` with `expectedType == Prop`.
355
+ Before we elaborate `s`, this method would be invoked, and `s.fType` is `?Ξ± Γ— ?Ξ² β†’ ?Ξ²` and after
356
+ propagation we would have `?Ξ± Γ— Prop β†’ Prop`. Then, when we would try to elaborate `s`, and
357
+ get a type error because `?Ξ± Γ— Prop` cannot be unified with `Nat Γ— Bool`.
358
+ Most users would have a hard time trying to understand why these examples failed.
359
+
360
+ Here is a possible alternative workaround. We give up the idea of using `Prop` at `if-then-else`.
361
+ Drawback: users use `if-then-else` with conditions that are not Decidable.
362
+ So, users would have to embrace `propDecidable` and `choice`.
363
+ This may not be that bad since the developers and users don't seem to care about constructivism.
364
+
365
+ We currently use a different workaround, we just don't propagate the expected type when it is `Prop`. -/
366
+ if expectedType.isProp then
367
+ modify fun s => { s with propagateExpected := false }
368
+ else
369
+ let numRemainingArgs := s.args.length
370
+ trace[Elab.app.propagateExpectedType] "etaArgs.size: {s.etaArgs.size}, numRemainingArgs: {numRemainingArgs}, fType: {s.fType}"
371
+ match getForallBody (← read).explicit numRemainingArgs s.namedArgs s.fType with
372
+ | none => pure ()
373
+ | some fTypeBody =>
374
+ unless fTypeBody.hasLooseBVars do
375
+ unless (← hasOptAutoParams fTypeBody) do
376
+ trySynthesizeAppInstMVars
377
+ trace[Elab.app.propagateExpectedType] "{expectedType} =?= {fTypeBody}"
378
+ if (← isDefEq expectedType fTypeBody) then
379
+ /- Note that we only set `propagateExpected := false` when propagation has succeeded. -/
380
+ modify fun s => { s with propagateExpected := false }
381
+
382
+ /-- This method executes after all application arguments have been processed. -/
383
+ private def finalize : M Expr := do
384
+ let s ← get
385
+ let mut e := s.f
386
+ -- all user explicit arguments have been consumed
387
+ trace[Elab.app.finalize] e
388
+ let ref ← getRef
389
+ -- Register the error context of implicits
390
+ for mvarId in s.toSetErrorCtx do
391
+ registerMVarErrorImplicitArgInfo mvarId ref e
392
+ if !s.etaArgs.isEmpty then
393
+ e ← mkLambdaFVars s.etaArgs e
394
+ /-
395
+ Remark: we should not use `s.fType` as `eType` even when
396
+ `s.etaArgs.isEmpty`. Reason: it may have been unfolded.
397
+ -/
398
+ let eType ← inferType e
399
+ trace[Elab.app.finalize] "after etaArgs, {e} : {eType}"
400
+ /- Recall that `resultTypeOutParam? = some mvarId` if the function result type is the output parameter
401
+ of a local instance. The value of this parameter may be inferable using other arguments. For example,
402
+ suppose we have
403
+ ```lean
404
+ def add_one {X} [Trait X] [One (Trait.R X)] [HAdd X (Trait.R X) X] (x : X) : X := x + (One.one : (Trait.R X))
405
+ ```
406
+ from test `948.lean`. There are multiple ways to infer `X`, and we don't want to mark it as `syntheticOpaque`.
407
+ -/
408
+ if let some outParamMVarId := s.resultTypeOutParam? then
409
+ synthesizeAppInstMVars
410
+ /- If `eType != mkMVar outParamMVarId`, then the
411
+ function is partially applied, and we do not apply default instances. -/
412
+ if !(← outParamMVarId.isAssigned) && eType.isMVar && eType.mvarId! == outParamMVarId then
413
+ synthesizeSyntheticMVarsUsingDefault
414
+ return e
415
+ else
416
+ return e
417
+ if let some expectedType := s.expectedType? then
418
+ trySynthesizeAppInstMVars
419
+ -- Try to propagate expected type. Ignore if types are not definitionally equal, caller must handle it.
420
+ trace[Elab.app.finalize] "expected type: {expectedType}"
421
+ discard <| isDefEq expectedType eType
422
+ synthesizeAppInstMVars
423
+ return e
424
+
425
+ /--
426
+ Returns a named argument that depends on the next argument, otherwise `none`.
427
+ -/
428
+ private def findNamedArgDependsOnCurrent? : M (Option NamedArg) := do
429
+ let s ← get
430
+ if s.namedArgs.isEmpty then
431
+ return none
432
+ else
433
+ forallTelescopeReducing s.fType fun xs _ => do
434
+ let curr := xs[0]!
435
+ for h : i in [1:xs.size] do
436
+ let xDecl ← xs[i].fvarId!.getDecl
437
+ if let some arg := s.namedArgs.find? fun arg => arg.name == xDecl.userName then
438
+ /- Remark: a default value at `optParam` does not count as a dependency -/
439
+ if (← exprDependsOn xDecl.type.cleanupAnnotations curr.fvarId!) then
440
+ return arg
441
+ return none
442
+
443
+
444
+ /-- Return `true` if there are regular or named arguments to be processed. -/
445
+ private def hasArgsToProcess : M Bool := do
446
+ let s ← get
447
+ return !s.args.isEmpty || !s.namedArgs.isEmpty
448
+
449
+ /--
450
+ Returns the argument syntax if the next argument at `args` is of the form `_`.
451
+ -/
452
+ private def nextArgHole? : M (Option Syntax) := do
453
+ match (← get).args with
454
+ | Arg.stx stx@(Syntax.node _ ``Lean.Parser.Term.hole _) :: _ => pure stx
455
+ | _ => pure none
456
+
457
+ /--
458
+ Return `true` if the next argument to be processed is the outparam of a local instance, and it the result type
459
+ of the function.
460
+
461
+ For example, suppose we have the class
462
+ ```lean
463
+ class Get (Cont : Type u) (Idx : Type v) (Elem : outParam (Type w)) where
464
+ get (xs : Cont) (i : Idx) : Elem
465
+ ```
466
+ And the current value of `fType` is
467
+ ```
468
+ {Cont : Type u_1} β†’ {Idx : Type u_2} β†’ {Elem : Type u_3} β†’ [self : Get Cont Idx Elem] β†’ Cont β†’ Idx β†’ Elem
469
+ ```
470
+ then the result returned by this method is `false` since `Cont` is not the output param of any local instance.
471
+ Now assume `fType` is
472
+ ```
473
+ {Elem : Type u_3} β†’ [self : Get Cont Idx Elem] β†’ Cont β†’ Idx β†’ Elem
474
+ ```
475
+ then, the method returns `true` because `Elem` is an output parameter for the local instance `[self : Get Cont Idx Elem]`.
476
+
477
+ Remark: if `resultIsOutParamSupport` is `false`, this method returns `false`.
478
+ -/
479
+ private partial def isNextOutParamOfLocalInstanceAndResult : M Bool := do
480
+ if !(← read).resultIsOutParamSupport then
481
+ return false
482
+ let type := (← get).fType.bindingBody!
483
+ unless isResultType type 0 do
484
+ return false
485
+ if (← hasLocalInstaceWithOutParams type) then
486
+ let x := mkFVar (← mkFreshFVarId)
487
+ isOutParamOfLocalInstance x (type.instantiate1 x)
488
+ else
489
+ return false
490
+ where
491
+ isResultType (type : Expr) (i : Nat) : Bool :=
492
+ match type with
493
+ | .forallE _ _ b _ => isResultType b (i + 1)
494
+ | .bvar idx => idx == i
495
+ | _ => false
496
+
497
+ /-- (quick filter) Return true if `type` contains a binder `[C ...]` where `C` is a class containing outparams. -/
498
+ hasLocalInstaceWithOutParams (type : Expr) : CoreM Bool := do
499
+ let .forallE _ d b bi := type | return false
500
+ if bi.isInstImplicit then
501
+ if let .const declName .. := d.getAppFn then
502
+ if hasOutParams (← getEnv) declName then
503
+ return true
504
+ hasLocalInstaceWithOutParams b
505
+
506
+ isOutParamOfLocalInstance (x : Expr) (type : Expr) : MetaM Bool := do
507
+ let .forallE _ d b bi := type | return false
508
+ if bi.isInstImplicit then
509
+ if let .const declName .. := d.getAppFn then
510
+ if hasOutParams (← getEnv) declName then
511
+ let cType ← inferType d.getAppFn
512
+ if (← isOutParamOf x 0 d.getAppArgs cType) then
513
+ return true
514
+ isOutParamOfLocalInstance x b
515
+
516
+ isOutParamOf (x : Expr) (i : Nat) (args : Array Expr) (cType : Expr) : MetaM Bool := do
517
+ if h : i < args.size then
518
+ match (← whnf cType) with
519
+ | .forallE _ d b _ =>
520
+ if args[i] == x && d.isOutParam then
521
+ return true
522
+ isOutParamOf x (i+1) args b
523
+ | _ => return false
524
+ else
525
+ return false
526
+
527
+ mutual
528
+ /--
529
+ Create a fresh local variable with the current binder name and argument type, add it to `etaArgs` and `f`,
530
+ and then execute the main loop.
531
+ -/
532
+ private partial def addEtaArg (argName : Name) : M Expr := do
533
+ let n ← getBindingName
534
+ let type ← getArgExpectedType
535
+ withLocalDeclD n type fun x => do
536
+ modify fun s => { s with etaArgs := s.etaArgs.push x }
537
+ addNewArg argName x
538
+ main
539
+
540
+ /--
541
+ Create a fresh metavariable for the implicit argument, add it to `f`, and then execute the main loop.
542
+ -/
543
+ private partial def addImplicitArg (argName : Name) : M Expr := do
544
+ let argType ← getArgExpectedType
545
+ let arg ← if (← isNextOutParamOfLocalInstanceAndResult) then
546
+ let arg ← mkFreshExprMVar argType
547
+ /- When the result type is an output parameter, we don't want to propagate the expected type.
548
+ So, we just mark `propagateExpected := false` to disable it.
549
+ At `finalize`, we check whether `arg` is still unassigned, if it is, we apply default instances,
550
+ and try to synthesize pending mvars. -/
551
+ modify fun s => { s with resultTypeOutParam? := some arg.mvarId!, propagateExpected := false }
552
+ pure arg
553
+ else
554
+ mkFreshExprMVar argType
555
+ modify fun s => { s with toSetErrorCtx := s.toSetErrorCtx.push arg.mvarId! }
556
+ addNewArg argName arg
557
+ main
558
+
559
+ /--
560
+ Process a `fType` of the form `(x : A) β†’ B x`.
561
+ This method assume `fType` is a function type.
562
+ -/
563
+ private partial def processExplicitArg (argName : Name) : M Expr := do
564
+ match (← get).args with
565
+ | arg::args =>
566
+ -- Note: currently the following test never succeeds in explicit mode since `@x.f` notation does not exist.
567
+ if let some true := NamedArg.suppressDeps <$> (← findNamedArgDependsOnCurrent?) then
568
+ /-
569
+ We treat the explicit argument `argName` as implicit
570
+ if we have a named arguments that depends on it whose `suppressDeps` flag set to `true`.
571
+ The motivation for this is class projections (issue #1851).
572
+ In some cases, class projections can have explicit parameters. For example, in
573
+ ```
574
+ class Approx {Ξ± : Type} (a : Ξ±) (X : Type) : Type where
575
+ val : X
576
+ ```
577
+ the type of `Approx.val` is `{Ξ± : Type} β†’ (a : Ξ±) β†’ {X : Type} β†’ [self : Approx a X] β†’ X`.
578
+ Note that the parameter `a` is explicit since there is no way to infer it from the expected
579
+ type or from the types of other explicit parameters.
580
+ Being a parameter of the class, `a` is determined by the type of `self`.
581
+
582
+ Consider
583
+ ```
584
+ variable {Ξ± Ξ² X Y : Type} {f' : Ξ± β†’ Ξ²} {x' : Ξ±} [f : Approx f' (X β†’ Y)]
585
+ ```
586
+ Recall that `f.val` is, to first approximation, sugar for `Approx.val (self := f)`.
587
+ Without further refinement, this would expand to `fun f'' : Ξ± β†’ Ξ² => Approx.val f'' f`,
588
+ which is a type error, since `f''` must be defeq to `f'`.
589
+ Furthermore, with projection notation, users expect all structure parameters
590
+ to be uniformly implicit; after all, they are determined by `self`.
591
+ To handle this, the `(self := f)` named argument is annotated with the `suppressDeps` flag.
592
+ This causes the `a` parameter to become implicit, and `f.val` instead expands to `Approx.val f' f`.
593
+
594
+ This feature previously was enabled for *all* explicit arguments, which confused users
595
+ and was frequently reported as a bug (issue #1867).
596
+ Now it is only enabled for the `self` argument in structure projections.
597
+
598
+ We used to do this only when `(← get).args` was empty,
599
+ but it created an asymmetry because `f.val` worked as expected,
600
+ yet one would have to write `f.val _ x` when there are further arguments.
601
+ -/
602
+ return (← addImplicitArg argName)
603
+ propagateExpectedType arg
604
+ modify fun s => { s with args }
605
+ elabAndAddNewArg argName arg
606
+ main
607
+ | _ =>
608
+ if (← read).ellipsis && (← readThe Term.Context).inPattern then
609
+ /-
610
+ In patterns, ellipsis should always be an implicit argument, even if it is an optparam or autoparam.
611
+ This prevents examples such as the one in #4555 from failing:
612
+ ```lean
613
+ match e with
614
+ | .internal .. => sorry
615
+ | .error .. => sorry
616
+ ```
617
+ The `internal` has an optparam (`| internal (id : InternalExceptionId) (extra : KVMap := {})`).
618
+
619
+ We may consider having ellipsis suppress optparams and autoparams in general.
620
+ We avoid doing so for now since it's possible to opt-out of them (for example with `.internal (extra := _) ..`)
621
+ but it's not possible to opt-in.
622
+ -/
623
+ return ← addImplicitArg argName
624
+ let argType ← getArgExpectedType
625
+ match (← read).explicit, argType.getOptParamDefault?, argType.getAutoParamTactic? with
626
+ | false, some defVal, _ => addNewArg argName defVal; main
627
+ | false, _, some (.const tacticDecl _) =>
628
+ let env ← getEnv
629
+ let opts ← getOptions
630
+ match evalSyntaxConstant env opts tacticDecl with
631
+ | Except.error err => throwError err
632
+ | Except.ok tacticSyntax =>
633
+ let tacticBlock ← `(by $(⟨tacticSyntax⟩))
634
+ /-
635
+ We insert position information from the current ref into `stx` everywhere, simulating this being
636
+ a tactic script inserted by the user, which ensures error messages and logging will always be attributed
637
+ to this application rather than sometimes being placed at position (1,0) in the file.
638
+ Placing position information on `by` syntax alone is not sufficient since incrementality
639
+ (in particular, `Lean.Elab.Term.withReuseContext`) controls the ref to avoid leakage of outside data.
640
+ Note that `tacticSyntax` contains no position information itself, since it is erased by `Lean.Elab.Term.quoteAutoTactic`.
641
+ -/
642
+ let info := (← getRef).getHeadInfo.nonCanonicalSynthetic
643
+ let tacticBlock := tacticBlock.raw.rewriteBottomUp (Β·.setInfo info)
644
+ let mvar ← mkTacticMVar argType.consumeTypeAnnotations tacticBlock (.autoParam argName)
645
+ -- Note(kmill): We are adding terminfo to simulate a previous implementation that elaborated `tacticBlock`.
646
+ -- We should look into removing this since terminfo for synthetic syntax is suspect,
647
+ -- but we noted it was necessary to preserve the behavior of the unused variable linter.
648
+ addTermInfo' tacticBlock mvar
649
+ let argNew := Arg.expr mvar
650
+ propagateExpectedType argNew
651
+ elabAndAddNewArg argName argNew
652
+ main
653
+ | false, _, some _ =>
654
+ throwError "invalid autoParam, argument must be a constant"
655
+ | _, _, _ =>
656
+ if (← read).ellipsis then
657
+ addImplicitArg argName
658
+ else if !(← get).namedArgs.isEmpty then
659
+ if let some _ ← findNamedArgDependsOnCurrent? then
660
+ /-
661
+ Dependencies of named arguments cannot be turned into eta arguments
662
+ since they are determined by the named arguments.
663
+ Instead we can turn them into implicit arguments.
664
+ -/
665
+ addImplicitArg argName
666
+ else
667
+ addEtaArg argName
668
+ else if !(← read).explicit then
669
+ if (← fTypeHasOptAutoParams) then
670
+ addEtaArg argName
671
+ else
672
+ finalize
673
+ else
674
+ finalize
675
+
676
+ /--
677
+ Process a `fType` of the form `{x : A} β†’ B x`.
678
+ This method assume `fType` is a function type -/
679
+ private partial def processImplicitArg (argName : Name) : M Expr := do
680
+ if (← read).explicit then
681
+ processExplicitArg argName
682
+ else
683
+ addImplicitArg argName
684
+
685
+ /--
686
+ Process a `fType` of the form `{{x : A}} β†’ B x`.
687
+ This method assume `fType` is a function type -/
688
+ private partial def processStrictImplicitArg (argName : Name) : M Expr := do
689
+ if (← read).explicit then
690
+ processExplicitArg argName
691
+ else if (← hasArgsToProcess) then
692
+ addImplicitArg argName
693
+ else
694
+ finalize
695
+
696
+ /--
697
+ Process a `fType` of the form `[x : A] β†’ B x`.
698
+ This method assume `fType` is a function type.
699
+ -/
700
+ private partial def processInstImplicitArg (argName : Name) : M Expr := do
701
+ if (← read).explicit then
702
+ if let some stx ← nextArgHole? then
703
+ -- We still use typeclass resolution for `_` arguments.
704
+ -- This behavior can be suppressed with `(_)`.
705
+ let ty ← getArgExpectedType
706
+ let arg ← mkInstMVar ty
707
+ addTermInfo' stx arg ty
708
+ modify fun s => { s with args := s.args.tail! }
709
+ main
710
+ else
711
+ processExplicitArg argName
712
+ else
713
+ discard <| mkInstMVar (← getArgExpectedType)
714
+ main
715
+ where
716
+ mkInstMVar (ty : Expr) : M Expr := do
717
+ let arg ← mkFreshExprMVar ty MetavarKind.synthetic
718
+ addInstMVar arg.mvarId!
719
+ addNewArg argName arg
720
+ return arg
721
+
722
+ /-- Elaborate function application arguments. -/
723
+ partial def main : M Expr := do
724
+ let fType ← normalizeFunType
725
+ if fType.isForall then
726
+ let binderName := fType.bindingName!
727
+ let binfo := fType.bindingInfo!
728
+ let s ← get
729
+ match findBinderName? s.namedArgs binderName with
730
+ | some namedArg =>
731
+ propagateExpectedType namedArg.val
732
+ eraseNamedArg binderName
733
+ elabAndAddNewArg binderName namedArg.val
734
+ main
735
+ | none =>
736
+ match binfo with
737
+ | .implicit => processImplicitArg binderName
738
+ | .instImplicit => processInstImplicitArg binderName
739
+ | .strictImplicit => processStrictImplicitArg binderName
740
+ | _ => processExplicitArg binderName
741
+ else if (← hasArgsToProcess) then
742
+ synthesizePendingAndNormalizeFunType
743
+ main
744
+ else
745
+ finalize
746
+
747
+ end
748
+
749
+ end ElabAppArgs
750
+
751
+
752
+ /-! # Eliminator-like function application elaborator -/
753
+
754
+ /--
755
+ Information about an eliminator used by the elab-as-elim elaborator.
756
+ This is not to be confused with `Lean.Meta.ElimInfo`, which is for `induction` and `cases`.
757
+ The elab-as-elim routine is less restrictive in what counts as an eliminator, and it doesn't need
758
+ to have a strict notion of what is a "target" β€” all it cares about are
759
+ 1. that the return type of a function is of the form `m ...` where `m` is a parameter
760
+ (unlike `induction` and `cases` eliminators, the arguments to `m`, known as "discriminants",
761
+ can be any expressions, not just parameters), and
762
+ 2. which arguments should be eagerly elaborated, to make discriminants be as elaborated as
763
+ possible for the expected type generalization procedure,
764
+ and which should be postponed (since they are the "minor premises").
765
+
766
+ Note that the routine isn't doing induction/cases *on* particular expressions.
767
+ The purpose of elab-as-elim is to successfully solve the higher-order unification problem
768
+ between the return type of the function and the expected type.
769
+ -/
770
+ structure ElabElimInfo where
771
+ /-- The eliminator. -/
772
+ elimExpr : Expr
773
+ /-- The type of the eliminator. -/
774
+ elimType : Expr
775
+ /-- The position of the motive parameter. -/
776
+ motivePos : Nat
777
+ /--
778
+ Positions of "major" parameters (those that should be eagerly elaborated
779
+ because they can contribute to the motive inference procedure).
780
+ All parameters that are neither the motive nor a major parameter are "minor" parameters.
781
+ The major parameters include all of the parameters that transitively appear in the motive's arguments,
782
+ as well as "first-order" arguments that include such parameters,
783
+ since they too can help with elaborating discriminants.
784
+
785
+ For example, in the following theorem the argument `h : a = b`
786
+ should be elaborated eagerly because it contains `b`, which occurs in `motive b`.
787
+ ```
788
+ theorem Eq.subst' {Ξ±} {motive : Ξ± β†’ Prop} {a b : Ξ±} (h : a = b) : motive a β†’ motive b
789
+ ```
790
+ For another example, the term `isEmptyElim (Ξ± := Ξ±)` is an underapplied eliminator, and it needs
791
+ argument `Ξ±` to be elaborated eagerly to create a type-correct motive.
792
+ ```
793
+ def isEmptyElim [IsEmpty Ξ±] {p : Ξ± β†’ Sort _} (a : Ξ±) : p a := ...
794
+ example {Ξ± : Type _} [IsEmpty Ξ±] : id (Ξ± β†’ False) := isEmptyElim (Ξ± := Ξ±)
795
+ ```
796
+ -/
797
+ majorsPos : Array Nat := #[]
798
+ deriving Repr, Inhabited
799
+
800
+ def getElabElimExprInfo (elimExpr : Expr) : MetaM ElabElimInfo := do
801
+ let elimType ← inferType elimExpr
802
+ trace[Elab.app.elab_as_elim] "eliminator {indentExpr elimExpr}\nhas type{indentExpr elimType}"
803
+ forallTelescopeReducing elimType fun xs type => do
804
+ let motive := type.getAppFn
805
+ let motiveArgs := type.getAppArgs
806
+ unless motive.isFVar && motiveArgs.size > 0 do
807
+ throwError "unexpected eliminator resulting type{indentExpr type}"
808
+ let motiveType ← inferType motive
809
+ forallTelescopeReducing motiveType fun motiveParams motiveResultType => do
810
+ unless motiveParams.size == motiveArgs.size do
811
+ throwError "unexpected number of arguments at motive type{indentExpr motiveType}"
812
+ unless motiveResultType.isSort do
813
+ throwError "motive result type must be a sort{indentExpr motiveType}"
814
+ let some motivePos := xs.idxOf? motive |
815
+ throwError "unexpected eliminator type{indentExpr elimType}"
816
+ /-
817
+ Compute transitive closure of fvars appearing in arguments to the motive.
818
+ These are the primary set of major parameters.
819
+ -/
820
+ let initMotiveFVars : CollectFVars.State := motiveArgs.foldl (init := {}) collectFVars
821
+ let motiveFVars ← xs.size.foldRevM (init := initMotiveFVars) fun i _ s => do
822
+ let x := xs[i]
823
+ if s.fvarSet.contains x.fvarId! then
824
+ return collectFVars s (← inferType x)
825
+ else
826
+ return s
827
+ /- Collect the major parameter positions -/
828
+ let mut majorsPos := #[]
829
+ for h : i in [:xs.size] do
830
+ let x := xs[i]
831
+ unless motivePos == i do
832
+ let xType ← x.fvarId!.getType
833
+ /-
834
+ We also consider "first-order" types because we can reliably "extract" information from them.
835
+ We say a term is "first-order" if all applications are of the form `f ...` where `f` is a constant.
836
+ -/
837
+ let isFirstOrder (e : Expr) : Bool := Option.isNone <| e.find? fun e => e.isApp && !e.getAppFn.isConst
838
+ if motiveFVars.fvarSet.contains x.fvarId!
839
+ || (isFirstOrder xType
840
+ && Option.isSome (xType.find? fun e => e.isFVar && motiveFVars.fvarSet.contains e.fvarId!)) then
841
+ majorsPos := majorsPos.push i
842
+ trace[Elab.app.elab_as_elim] "motivePos: {motivePos}"
843
+ trace[Elab.app.elab_as_elim] "majorsPos: {majorsPos}"
844
+ return { elimExpr, elimType, motivePos, majorsPos }
845
+
846
+ def getElabElimInfo (elimName : Name) : MetaM ElabElimInfo := do
847
+ getElabElimExprInfo (← mkConstWithFreshMVarLevels elimName)
848
+
849
+
850
+ /--
851
+ Instructs the elaborator that applications of this function should be elaborated like an eliminator.
852
+
853
+ An eliminator is a function that returns an application of a "motive" which is a parameter of the
854
+ form `_ β†’ ... β†’ Sort _`, i.e. a function that takes in a certain amount of arguments (referred to
855
+ as major premises) and returns a type in some universe. The `rec` and `casesOn` functions of
856
+ inductive types are automatically treated as eliminators, for other functions this attribute needs
857
+ to be used.
858
+
859
+ Eliminator elaboration can be compared to the `induction` tactic: The expected type is used as the
860
+ return value of the motive, with occurrences of the major premises replaced with the arguments.
861
+ When more arguments are specified than necessary, the remaining arguments are reverted into the
862
+ expected type.
863
+
864
+ Examples:
865
+ ```lean example
866
+ @[elab_as_elim]
867
+ def evenOddRecOn {motive : Nat β†’ Sort u}
868
+ (even : βˆ€ n, motive (n * 2)) (odd : βˆ€ n, motive (n * 2 + 1))
869
+ (n : Nat) : motive n := ...
870
+
871
+ -- simple usage
872
+ example (a : Nat) : (a * a) % 2 = a % 2 :=
873
+ evenOddRec _ _ a
874
+ /-
875
+ 1. basic motive is `fun n => (a + 2) % 2 = a % 2`
876
+ 2. major premise `a` substituted: `fun n => (n + 2) % 2 = n % 2`
877
+ 3. now elaborate the other parameters as usual:
878
+ "even" (first hole): expected type `βˆ€ n, ((n * 2) * (n * 2)) % 2 = (n * 2) % 2`,
879
+ "odd" (second hole): expected type `βˆ€ n, ((n * 2 + 1) * (n * 2 + 1)) % 2 = (n * 2 + 1) % 2`
880
+ -/
881
+
882
+ -- complex substitution
883
+ example (a : Nat) (f : Nat β†’ Nat) : (f a + 1) % 2 β‰  f a :=
884
+ evenOddRec _ _ (f a)
885
+ /-
886
+ Similar to before, except `f a` is substituted: `motive := fun n => (n + 1) % 2 β‰  n`.
887
+ Now the first hole has expected type `βˆ€ n, (n * 2 + 1) % 2 β‰  n * 2`.
888
+ Now the second hole has expected type `βˆ€ n, (n * 2 + 1 + 1) % 2 β‰  n * 2 + 1`.
889
+ -/
890
+
891
+ -- more parameters
892
+ example (a : Nat) (h : a % 2 = 1) : (a + 1) % 2 = 0 :=
893
+ evenOddRec _ _ a h
894
+ /-
895
+ Before substitution, `a % 2 = 1` is reverted: `motive := fun n => a % 2 = 0 β†’ (a + 1) % 2 = 0`.
896
+ Substitution: `motive := fun n => n % 2 = 1 β†’ (n + 1) % 2 = 0`
897
+ Now the first hole has expected type `βˆ€ n, n * 2 % 2 = 1 β†’ (n * 2) % 2 = 0`.
898
+ Now the second hole has expected type `βˆ€ n, (n * 2 + 1) % 2 = 1 β†’ (n * 2 + 1) % 2 = 0`.
899
+ -/
900
+ ```
901
+
902
+ See also `@[induction_eliminator]` and `@[cases_eliminator]` for registering default eliminators.
903
+ -/
904
+ @[builtin_doc]
905
+ builtin_initialize elabAsElim : TagAttribute ←
906
+ registerTagAttribute `elab_as_elim
907
+ "instructs elaborator that the arguments of the function application should be elaborated as were an eliminator"
908
+ /-
909
+ We apply `elab_as_elim` after compilation because this kind of attribute is not applied to auxiliary declarations
910
+ created by the `WF` and `Structural` modules. This is an "indirect" fix for issue #1900. We should consider
911
+ having an explicit flag in attributes to indicate whether they should be copied to auxiliary declarations or not.
912
+ -/
913
+ (applicationTime := .afterCompilation)
914
+ fun declName => do
915
+ let go : MetaM Unit := do
916
+ let info ← getConstInfo declName
917
+ if (← hasOptAutoParams info.type) then
918
+ throwError "[elab_as_elim] attribute cannot be used in declarations containing optional and auto parameters"
919
+ discard <| getElabElimInfo declName
920
+ go.run' {} {}
921
+
922
+ namespace ElabElim
923
+
924
+ /-- Context of the `elab_as_elim` elaboration procedure. -/
925
+ structure Context where
926
+ elimInfo : ElabElimInfo
927
+ expectedType : Expr
928
+
929
+ /-- State of the `elab_as_elim` elaboration procedure. -/
930
+ structure State where
931
+ /-- The resultant expression being built. -/
932
+ f : Expr
933
+ /-- `f : fType -/
934
+ fType : Expr
935
+ /-- User-provided named arguments that still have to be processed. -/
936
+ namedArgs : List NamedArg
937
+ /-- User-provided arguments that still have to be processed. -/
938
+ args : List Arg
939
+ /-- Instance implicit arguments collected so far. -/
940
+ instMVars : Array MVarId := #[]
941
+ /-- Position of the next argument to be processed. We use it to decide whether the argument is the motive or a discriminant. -/
942
+ idx : Nat := 0
943
+ /-- Store the metavariable used to represent the motive that will be computed at `finalize`. -/
944
+ motive? : Option Expr := none
945
+
946
+ abbrev M := ReaderT Context $ StateRefT State TermElabM
947
+
948
+ /-- Infer the `motive` using the expected type by `kabstract`ing the discriminants. -/
949
+ def mkMotive (discrs : Array Expr) (expectedType : Expr) : MetaM Expr := do
950
+ discrs.foldrM (init := expectedType) fun discr motive => do
951
+ let discr ← instantiateMVars discr
952
+ let motiveBody ← kabstract motive discr
953
+ /- We use `transform (usedLetOnly := true)` to eliminate unnecessary let-expressions. -/
954
+ let discrType ← transform (usedLetOnly := true) (← instantiateMVars (← inferType discr))
955
+ return Lean.mkLambda (← mkFreshBinderName) BinderInfo.default discrType motiveBody
956
+
957
+ /--
958
+ If the eliminator is over-applied, we "revert" the extra arguments.
959
+ Returns the function with the reverted arguments applied and the new generalized expected type.
960
+ -/
961
+ def revertArgs (args : List Arg) (f : Expr) (expectedType : Expr) : TermElabM (Expr Γ— Expr) := do
962
+ let (xs, expectedType) ← args.foldrM (init := ([], expectedType)) fun arg (xs, expectedType) => do
963
+ let val ←
964
+ match arg with
965
+ | .expr val => pure val
966
+ | .stx stx => elabTerm stx none
967
+ let val ← instantiateMVars val
968
+ let expectedTypeBody ← kabstract expectedType val
969
+ /- We use `transform (usedLetOnly := true)` to eliminate unnecessary let-expressions. -/
970
+ let valType ← transform (usedLetOnly := true) (← instantiateMVars (← inferType val))
971
+ return (val :: xs, mkForall (← mkFreshBinderName) BinderInfo.default valType expectedTypeBody)
972
+ return (xs.foldl .app f, expectedType)
973
+
974
+ /--
975
+ Construct the resulting application after all discriminants have been elaborated, and we have
976
+ consumed as many given arguments as possible.
977
+ -/
978
+ def finalize : M Expr := do
979
+ unless (← get).namedArgs.isEmpty do
980
+ throwError "failed to elaborate eliminator, unused named arguments: {(← get).namedArgs.map (Β·.name)}"
981
+ let some motive := (← get).motive?
982
+ | throwError "failed to elaborate eliminator, insufficient number of arguments"
983
+ trace[Elab.app.elab_as_elim] "motive: {motive}"
984
+ forallTelescope (← get).fType fun xs fType => do
985
+ trace[Elab.app.elab_as_elim] "xs: {xs}"
986
+ let mut expectedType := (← read).expectedType
987
+ trace[Elab.app.elab_as_elim] "expectedType:{indentD expectedType}"
988
+ let throwInsufficient := do
989
+ throwError "failed to elaborate eliminator, insufficient number of arguments, expected type:{indentExpr expectedType}"
990
+ let mut f := (← get).f
991
+ if xs.size > 0 then
992
+ -- under-application, specialize the expected type using `xs`
993
+ -- Note: if we ever wanted to support optParams and autoParams, this is where it could be.
994
+ assert! (← get).args.isEmpty
995
+ for x in xs do
996
+ let .forallE _ t b _ ← whnf expectedType | throwInsufficient
997
+ unless ← fullApproxDefEq <| isDefEq t (← inferType x) do
998
+ -- We can't assume that these binding domains were supposed to line up, so report insufficient arguments
999
+ throwInsufficient
1000
+ expectedType := b.instantiate1 x
1001
+ trace[Elab.app.elab_as_elim] "xs after specialization of expected type: {xs}"
1002
+ else
1003
+ -- over-application, simulate `revert` while generalizing the values of these arguments in the expected type
1004
+ (f, expectedType) ← revertArgs (← get).args f expectedType
1005
+ unless ← isTypeCorrect expectedType do
1006
+ throwError "failed to elaborate eliminator, after generalizing over-applied arguments, expected type is type incorrect:{indentExpr expectedType}"
1007
+ trace[Elab.app.elab_as_elim] "expectedType after processing:{indentD expectedType}"
1008
+ let result := mkAppN f xs
1009
+ trace[Elab.app.elab_as_elim] "result:{indentD result}"
1010
+ unless fType.getAppFn == (← get).motive? do
1011
+ throwError "Internal error, eliminator target type isn't an application of the motive"
1012
+ let discrs := fType.getAppArgs
1013
+ trace[Elab.app.elab_as_elim] "discrs: {discrs}"
1014
+ let motiveVal ← mkMotive discrs expectedType
1015
+ unless (← isTypeCorrect motiveVal) do
1016
+ throwError "failed to elaborate eliminator, motive is not type correct:{indentD motiveVal}"
1017
+ unless (← isDefEq motive motiveVal) do
1018
+ throwError "failed to elaborate eliminator, invalid motive{indentExpr motiveVal}"
1019
+ synthesizeAppInstMVars (← get).instMVars result
1020
+ trace[Elab.app.elab_as_elim] "completed motive:{indentD motive}"
1021
+ let result ← mkLambdaFVars xs (← instantiateMVars result)
1022
+ return result
1023
+
1024
+ /--
1025
+ Return the next argument to be processed.
1026
+ The result is `.none` if it is an implicit argument which was not provided using a named argument.
1027
+ The result is `.undef` if `args` is empty and `namedArgs` does contain an entry for `binderName`.
1028
+ -/
1029
+ def getNextArg? (binderName : Name) (binderInfo : BinderInfo) : M (LOption Arg) := do
1030
+ match findBinderName? (← get).namedArgs binderName with
1031
+ | some namedArg =>
1032
+ modify fun s => { s with namedArgs := eraseNamedArg s.namedArgs binderName }
1033
+ return .some namedArg.val
1034
+ | none =>
1035
+ if binderInfo.isExplicit then
1036
+ match (← get).args with
1037
+ | [] => return .undef
1038
+ | arg :: args =>
1039
+ modify fun s => { s with args }
1040
+ return .some arg
1041
+ else
1042
+ return .none
1043
+
1044
+ /-- Set the `motive` field in the state. -/
1045
+ def setMotive (motive : Expr) : M Unit :=
1046
+ modify fun s => { s with motive? := motive }
1047
+
1048
+ /-- Elaborate the given argument with the given expected type. -/
1049
+ private def elabArg (arg : Arg) (argExpectedType : Expr) : M Expr := do
1050
+ match arg with
1051
+ | Arg.expr val => ensureArgType (← get).f val argExpectedType
1052
+ | Arg.stx stx =>
1053
+ let val ← elabTerm stx argExpectedType
1054
+ withRef stx <| ensureArgType (← get).f val argExpectedType
1055
+
1056
+ /-- Save information for producing error messages. -/
1057
+ def saveArgInfo (arg : Expr) (binderName : Name) : M Unit := do
1058
+ if arg.isMVar then
1059
+ registerMVarArgName arg.mvarId! binderName
1060
+
1061
+ /-- Create an implicit argument using the given `BinderInfo`. -/
1062
+ def mkImplicitArg (argExpectedType : Expr) (bi : BinderInfo) : M Expr := do
1063
+ let arg ← mkFreshExprMVar argExpectedType (if bi.isInstImplicit then .synthetic else .natural)
1064
+ if bi.isInstImplicit then
1065
+ modify fun s => { s with instMVars := s.instMVars.push arg.mvarId! }
1066
+ return arg
1067
+
1068
+ /-- Main loop of the `elimAsElab` procedure. -/
1069
+ partial def main : M Expr := do
1070
+ let .forallE binderName binderType body binderInfo ← whnfForall (← get).fType |
1071
+ finalize
1072
+ let addArgAndContinue (arg : Expr) : M Expr := do
1073
+ modify fun s => { s with idx := s.idx + 1, f := mkApp s.f arg, fType := body.instantiate1 arg }
1074
+ saveArgInfo arg binderName
1075
+ main
1076
+ let idx := (← get).idx
1077
+ if (← read).elimInfo.motivePos == idx then
1078
+ let motive ←
1079
+ match (← getNextArg? binderName binderInfo) with
1080
+ | .some arg =>
1081
+ /- Due to `Lean.Elab.Term.elabAppArgs.elabAsElim?`, this must be a positional argument that is the syntax `_`. -/
1082
+ elabArg arg binderType
1083
+ | .none | .undef =>
1084
+ /- Note: undef occurs when the motive is explicit but missing.
1085
+ In this case, we treat it as if it were an implicit argument
1086
+ to support writing `h.rec` when `h : False`, rather than requiring `h.rec _`. -/
1087
+ mkImplicitArg binderType binderInfo
1088
+ setMotive motive
1089
+ addArgAndContinue motive
1090
+ else if (← read).elimInfo.majorsPos.contains idx then
1091
+ match (← getNextArg? binderName binderInfo) with
1092
+ | .some arg => let discr ← elabArg arg binderType; addArgAndContinue discr
1093
+ | .undef => finalize
1094
+ | .none => let discr ← mkImplicitArg binderType binderInfo; addArgAndContinue discr
1095
+ else match (← getNextArg? binderName binderInfo) with
1096
+ | .some (.stx stx) => addArgAndContinue (← postponeElabTerm stx binderType)
1097
+ | .some (.expr val) => addArgAndContinue (← ensureArgType (← get).f val binderType)
1098
+ | .undef => finalize
1099
+ | .none => addArgAndContinue (← mkImplicitArg binderType binderInfo)
1100
+
1101
+ end ElabElim
1102
+
1103
+ /-- Return `true` if `declName` is a candidate for `ElabElim.main` elaboration. -/
1104
+ private def shouldElabAsElim (declName : Name) : CoreM Bool := do
1105
+ if (← isRec declName) then return true
1106
+ let env ← getEnv
1107
+ if isCasesOnRecursor env declName then return true
1108
+ if isBRecOnRecursor env declName then return true
1109
+ if isRecOnRecursor env declName then return true
1110
+ return elabAsElim.hasTag env declName
1111
+
1112
+ private def propagateExpectedTypeFor (f : Expr) : TermElabM Bool :=
1113
+ match f.getAppFn.constName? with
1114
+ | some declName => return !hasElabWithoutExpectedType (← getEnv) declName
1115
+ | _ => return true
1116
+
1117
+ /-! # Function application elaboration -/
1118
+
1119
+ /--
1120
+ Elaborate a `f`-application using `namedArgs` and `args` as the arguments.
1121
+ - `expectedType?` the expected type if available. It is used to propagate typing information only. This method does **not** ensure the result has this type.
1122
+ - `explicit = true` when notation `@` is used, and implicit arguments are assumed to be provided at `namedArgs` and `args`.
1123
+ - `ellipsis = true` when notation `..` is used. That is, we add `_` for missing arguments.
1124
+ - `resultIsOutParamSupport` is used to control whether special support is used when processing applications of functions that return
1125
+ output parameter of some local instance. Example:
1126
+ ```
1127
+ GetElem.getElem : {Cont : Type u_1} β†’ {Idx : Type u_2} β†’ {elem : Type u_3} β†’ {dom : cont β†’ idx β†’ Prop} β†’ [self : GetElem cont idx elem dom] β†’ (xs : cont) β†’ (i : idx) β†’ dom xs i β†’ elem
1128
+ ```
1129
+ The result type `elem` is the output parameter of the local instance `self`.
1130
+ When this parameter is set to `true`, we execute `synthesizeSyntheticMVarsUsingDefault`. For additional details, see comment at
1131
+ `ElabAppArgs.resultIsOutParam`.
1132
+ -/
1133
+ def elabAppArgs (f : Expr) (namedArgs : Array NamedArg) (args : Array Arg)
1134
+ (expectedType? : Option Expr) (explicit ellipsis : Bool) (resultIsOutParamSupport := true) : TermElabM Expr := do
1135
+ -- Coercions must be available to use this flag.
1136
+ -- If `@` is used (i.e., `explicit = true`), we disable `resultIsOutParamSupport`.
1137
+ let resultIsOutParamSupport := ((← getEnv).contains ``Lean.Internal.coeM) && resultIsOutParamSupport && !explicit
1138
+ let fType ← inferType f
1139
+ let fType ← instantiateMVars fType
1140
+ unless namedArgs.isEmpty && args.isEmpty do
1141
+ tryPostponeIfMVar fType
1142
+ trace[Elab.app.args] "explicit: {explicit}, ellipsis: {ellipsis}, {f} : {fType}"
1143
+ trace[Elab.app.args] "namedArgs: {namedArgs}"
1144
+ trace[Elab.app.args] "args: {args}"
1145
+ if let some elimInfo ← elabAsElim? then
1146
+ tryPostponeIfNoneOrMVar expectedType?
1147
+ let some expectedType := expectedType? | throwError "failed to elaborate eliminator, expected type is not available"
1148
+ let expectedType ← instantiateMVars expectedType
1149
+ if expectedType.getAppFn.isMVar then throwError "failed to elaborate eliminator, expected type is not available"
1150
+ ElabElim.main.run { elimInfo, expectedType } |>.run' {
1151
+ f, fType
1152
+ args := args.toList
1153
+ namedArgs := namedArgs.toList
1154
+ }
1155
+ else
1156
+ ElabAppArgs.main.run { explicit, ellipsis, resultIsOutParamSupport } |>.run' {
1157
+ args := args.toList
1158
+ expectedType?, f, fType
1159
+ namedArgs := namedArgs.toList
1160
+ propagateExpected := (← propagateExpectedTypeFor f)
1161
+ }
1162
+ where
1163
+ /-- Return `some info` if we should elaborate as an eliminator. -/
1164
+ elabAsElim? : TermElabM (Option ElabElimInfo) := do
1165
+ unless (← read).heedElabAsElim do return none
1166
+ if explicit || ellipsis then return none
1167
+ let .const declName _ := f | return none
1168
+ unless (← shouldElabAsElim declName) do return none
1169
+ let elimInfo ← getElabElimInfo declName
1170
+ forallTelescopeReducing (← inferType f) fun xs _ => do
1171
+ /- Process arguments similar to `Lean.Elab.Term.ElabElim.main` to see if the motive has been
1172
+ provided, in which case we use the standard app elaborator.
1173
+ If the motive is explicit (like for `False.rec`), then a positional `_` counts as "not provided". -/
1174
+ let mut args := args.toList
1175
+ let mut namedArgs := namedArgs.toList
1176
+ for x in xs[*...elimInfo.motivePos] do
1177
+ let localDecl ← x.fvarId!.getDecl
1178
+ match findBinderName? namedArgs localDecl.userName with
1179
+ | some _ => namedArgs := eraseNamedArg namedArgs localDecl.userName
1180
+ | none => if localDecl.binderInfo.isExplicit then args := args.tailD []
1181
+ -- Invariant: `elimInfo.motivePos < xs.size` due to construction of `elimInfo`.
1182
+ let some x := xs[elimInfo.motivePos]? | unreachable!
1183
+ let localDecl ← x.fvarId!.getDecl
1184
+ if findBinderName? namedArgs localDecl.userName matches some _ then
1185
+ -- motive has been explicitly provided, so we should use standard app elaborator
1186
+ return none
1187
+ else
1188
+ match localDecl.binderInfo.isExplicit, args with
1189
+ | true, .expr _ :: _ =>
1190
+ -- motive has been explicitly provided, so we should use standard app elaborator
1191
+ return none
1192
+ | true, .stx arg :: _ =>
1193
+ if arg.isOfKind ``Lean.Parser.Term.hole then
1194
+ return some elimInfo
1195
+ else
1196
+ -- positional motive is not `_`, so we should use standard app elaborator
1197
+ return none
1198
+ | _, _ => return some elimInfo
1199
+
1200
+
1201
+ /-- Auxiliary inductive datatype that represents the resolution of an `LVal`. -/
1202
+ inductive LValResolution where
1203
+ /-- When applied to `f`, effectively expands to `BaseStruct.fieldName (self := Struct.toBase f)`.
1204
+ This is a special named argument where it suppresses any explicit arguments depending on it so that type parameters don't need to be supplied. -/
1205
+ | projFn (baseStructName : Name) (structName : Name) (fieldName : Name)
1206
+ /-- Similar to `projFn`, but for extracting field indexed by `idx`. Works for structure-like inductive types in general. -/
1207
+ | projIdx (structName : Name) (idx : Nat)
1208
+ /-- When applied to `f`, effectively expands to `constName ... (Struct.toBase f)`, with the argument placed in the correct
1209
+ positional argument if possible, or otherwise as a named argument. The `Struct.toBase` is not present if `baseStructName == structName`,
1210
+ in which case these do not need to be structures. Supports generalized field notation. -/
1211
+ | const (baseStructName : Name) (structName : Name) (constName : Name)
1212
+ /-- Like `const`, but with `fvar` instead of `constName`.
1213
+ The `fullName` is the name of the recursive function, and `baseName` is the base name of the type to search for in the parameter list. -/
1214
+ | localRec (baseName : Name) (fullName : Name) (fvar : Expr)
1215
+
1216
+ private def throwLValErrorAt (ref : Syntax) (e : Expr) (eType : Expr) (msg : MessageData) : TermElabM Ξ± :=
1217
+ throwErrorAt ref "{msg}{indentExpr e}\nhas type{indentExpr eType}"
1218
+
1219
+ private def throwLValError (e : Expr) (eType : Expr) (msg : MessageData) : TermElabM Ξ± := do
1220
+ throwLValErrorAt (← getRef) e eType msg
1221
+
1222
+ /--
1223
+ `findMethod? S fName` tries the for each namespace `S'` in the resolution order for `S` to resolve the name `S'.fname`.
1224
+ If it resolves to `name`, returns `(S', name)`.
1225
+ -/
1226
+ private partial def findMethod? (structName fieldName : Name) : MetaM (Option (Name Γ— Name)) := do
1227
+ let env ← getEnv
1228
+ let find? structName' : MetaM (Option (Name Γ— Name)) := do
1229
+ let fullName := structName' ++ fieldName
1230
+ -- We do not want to make use of the current namespace for resolution.
1231
+ let candidates := ResolveName.resolveGlobalName (← getEnv) Name.anonymous (← getOpenDecls) fullName
1232
+ |>.filter (fun (_, fieldList) => fieldList.isEmpty)
1233
+ |>.map Prod.fst
1234
+ match candidates with
1235
+ | [] => return none
1236
+ | [fullName'] => return some (structName', fullName')
1237
+ | _ =>
1238
+ let candidates := MessageData.joinSep (candidates.map (m!"`{.ofConstName Β·}`")) ", "
1239
+ throwError "Field name `{fieldName}` is ambiguous: `{fullName}` has possible interpretations {candidates}"
1240
+ -- Optimization: the first element of the resolution order is `structName`,
1241
+ -- so we can skip computing the resolution order in the common case
1242
+ -- of the name resolving in the `structName` namespace.
1243
+ find? structName <||> do
1244
+ let resolutionOrder ← if isStructure env structName then getStructureResolutionOrder structName else pure #[structName]
1245
+ for ns in resolutionOrder[1...resolutionOrder.size] do
1246
+ if let some res ← find? ns then
1247
+ return res
1248
+ return none
1249
+
1250
+ private def throwInvalidFieldNotation (e eType : Expr) : TermElabM Ξ± :=
1251
+ throwLValError e eType "Invalid field notation: Type is not of the form `C ...` where C is a constant"
1252
+
1253
+ private def resolveLValAux (e : Expr) (eType : Expr) (lval : LVal) : TermElabM LValResolution := do
1254
+ if eType.isForall then
1255
+ match lval with
1256
+ | LVal.fieldName _ fieldName suffix? fullRef =>
1257
+ let fullName := Name.str `Function fieldName
1258
+ if (← getEnv).contains fullName then
1259
+ return LValResolution.const `Function `Function fullName
1260
+ else if suffix?.isNone then
1261
+ /- If there's no suffix, this could only have been a field in the `Function` namespace, so
1262
+ we needn't wait to check if this is actually a constant. If `suffix?` is non-`none`, we
1263
+ prefer to throw the "unknown constant" error (because of monad namespaces like `IO` and
1264
+ auxiliary declarations like `mutual_induct`) -/
1265
+ throwLValErrorAt fullRef e eType <| mkUnknownIdentifierMessage m!"Invalid field `{fieldName}`: \
1266
+ The environment does not contain `{Name.str `Function fieldName}`"
1267
+ | .fieldIdx .. =>
1268
+ throwLValError e eType "Invalid projection: Projections cannot be used on functions"
1269
+ else if eType.getAppFn.isMVar then
1270
+ let (kind, name) :=
1271
+ match lval with
1272
+ | .fieldName _ fieldName _ _ => (m!"field notation", m!"field `{fieldName}`")
1273
+ | .fieldIdx _ i => (m!"projection", m!"projection `{i}`")
1274
+ throwError "Invalid {kind}: Type of{indentExpr e}\nis not known; cannot resolve {name}"
1275
+ match eType.getAppFn.constName?, lval with
1276
+ | some structName, LVal.fieldIdx _ idx =>
1277
+ if idx == 0 then
1278
+ throwError "Invalid projection: Index must be greater than 0"
1279
+ let env ← getEnv
1280
+ let failK _ := throwLValError e eType "Invalid projection: Expected a value whose type is a structure"
1281
+ matchConstStructure eType.getAppFn failK fun _ _ ctorVal => do
1282
+ let numFields := ctorVal.numFields
1283
+ if idx - 1 < numFields then
1284
+ if isStructure env structName then
1285
+ let fieldNames := getStructureFields env structName
1286
+ return LValResolution.projFn structName structName fieldNames[idx - 1]!
1287
+ else
1288
+ /- `structName` was declared using `inductive` command.
1289
+ So, we don't projection functions for it. Thus, we use `Expr.proj` -/
1290
+ return LValResolution.projIdx structName (idx - 1)
1291
+ else
1292
+ let (fields, bounds) := if numFields == 1 then
1293
+ (m!"field", m!"the only valid index is 1")
1294
+ else
1295
+ (m!"fields", m!"it must be between 1 and {numFields}")
1296
+ throwError m!"Invalid projection: Index `{idx}` is invalid for this structure; {bounds}"
1297
+ ++ .note m!"The expression{inlineExpr e}has type{inlineExpr eType}which has only {numFields} {fields}"
1298
+ | some structName, LVal.fieldName _ fieldName _ fullRef =>
1299
+ let env ← getEnv
1300
+ if isStructure env structName then
1301
+ if let some baseStructName := findField? env structName (Name.mkSimple fieldName) then
1302
+ return LValResolution.projFn baseStructName structName (Name.mkSimple fieldName)
1303
+ -- Search the local context first
1304
+ let fullName := Name.mkStr structName fieldName
1305
+ for localDecl in (← getLCtx) do
1306
+ if localDecl.isAuxDecl then
1307
+ if let some localDeclFullName := (← getLCtx).auxDeclToFullName.find? localDecl.fvarId then
1308
+ if fullName == (privateToUserName? localDeclFullName).getD localDeclFullName then
1309
+ /- LVal notation is being used to make a "local" recursive call. -/
1310
+ return LValResolution.localRec structName fullName localDecl.toExpr
1311
+ -- Then search the environment
1312
+ if let some (baseStructName, fullName) ← findMethod? structName (.mkSimple fieldName) then
1313
+ return LValResolution.const baseStructName structName fullName
1314
+ let msg := mkUnknownIdentifierMessage m!"Invalid field `{fieldName}`: The environment does not contain `{Name.mkStr structName fieldName}`"
1315
+ throwLValErrorAt fullRef e eType msg
1316
+ | none, LVal.fieldName _ _ (some suffix) fullRef =>
1317
+ -- This may be a function constant whose implicit arguments have already been filled in:
1318
+ let c := e.getAppFn
1319
+ if c.isConst then
1320
+ throwUnknownConstantAt fullRef (c.constName! ++ suffix)
1321
+ else
1322
+ throwInvalidFieldNotation e eType
1323
+ | _, _ => throwInvalidFieldNotation e eType
1324
+
1325
+ /-- whnfCore + implicit consumption.
1326
+ Example: given `e` with `eType := {Ξ± : Type} β†’ (fun Ξ² => List Ξ²) Ξ± `, it produces `(e ?m, List ?m)` where `?m` is fresh metavariable. -/
1327
+ private partial def consumeImplicits (stx : Syntax) (e eType : Expr) (hasArgs : Bool) : TermElabM (Expr Γ— Expr) := do
1328
+ let eType ← whnfCore eType
1329
+ match eType with
1330
+ | .forallE _ d b bi =>
1331
+ if bi.isImplicit || (hasArgs && bi.isStrictImplicit) then
1332
+ let mvar ← mkFreshExprMVar d
1333
+ registerMVarErrorHoleInfo mvar.mvarId! stx
1334
+ consumeImplicits stx (mkApp e mvar) (b.instantiate1 mvar) hasArgs
1335
+ else if bi.isInstImplicit then
1336
+ let mvar ← mkInstMVar d
1337
+ let r := mkApp e mvar
1338
+ registerMVarErrorImplicitArgInfo mvar.mvarId! stx r
1339
+ consumeImplicits stx r (b.instantiate1 mvar) hasArgs
1340
+ else match d.getOptParamDefault? with
1341
+ | some defVal => consumeImplicits stx (mkApp e defVal) (b.instantiate1 defVal) hasArgs
1342
+ -- TODO: we do not handle autoParams here.
1343
+ | _ => return (e, eType)
1344
+ | _ => return (e, eType)
1345
+
1346
+ private partial def resolveLValLoop (lval : LVal) (e eType : Expr) (previousExceptions : Array Exception) (hasArgs : Bool) : TermElabM (Expr Γ— LValResolution) := do
1347
+ let (e, eType) ← consumeImplicits lval.getRef e eType hasArgs
1348
+ tryPostponeIfMVar eType
1349
+ /- If `eType` is still a metavariable application, we try to apply default instances to "unblock" it. -/
1350
+ if (← isMVarApp eType) then
1351
+ synthesizeSyntheticMVarsUsingDefault
1352
+ let eType ← instantiateMVars eType
1353
+ try
1354
+ let lvalRes ← resolveLValAux e eType lval
1355
+ return (e, lvalRes)
1356
+ catch
1357
+ | ex@(Exception.error _ _) =>
1358
+ let eType? ← unfoldDefinition? eType
1359
+ match eType? with
1360
+ | some eType => resolveLValLoop lval e eType (previousExceptions.push ex) hasArgs
1361
+ | none =>
1362
+ previousExceptions.forM fun ex => logException ex
1363
+ throw ex
1364
+ | ex@(Exception.internal _ _) => throw ex
1365
+
1366
+ private def resolveLVal (e : Expr) (lval : LVal) (hasArgs : Bool) : TermElabM (Expr Γ— LValResolution) := do
1367
+ let eType ← inferType e
1368
+ resolveLValLoop lval e eType #[] hasArgs
1369
+
1370
+ private partial def mkBaseProjections (baseStructName : Name) (structName : Name) (e : Expr) : TermElabM Expr := do
1371
+ let env ← getEnv
1372
+ match getPathToBaseStructure? env baseStructName structName with
1373
+ | none => throwError "Internal error: Failed to access field in parent structure"
1374
+ | some path =>
1375
+ let mut e := e
1376
+ for projFunName in path do
1377
+ let projFn ← mkConst projFunName
1378
+ e ← elabAppArgs projFn #[{ name := `self, val := Arg.expr e, suppressDeps := true }] (args := #[]) (expectedType? := none) (explicit := false) (ellipsis := false)
1379
+ return e
1380
+
1381
+ private partial def typeMatchesBaseName (type : Expr) (baseName : Name) : MetaM Bool :=
1382
+ withReducibleAndInstances do
1383
+ if baseName == `Function then
1384
+ return (← whnf type).isForall
1385
+ else if type.cleanupAnnotations.isAppOf baseName then
1386
+ return true
1387
+ else
1388
+ let type ← whnfCore type
1389
+ if type.isAppOf baseName then
1390
+ return true
1391
+ else
1392
+ match ← unfoldDefinition? type with
1393
+ | some type' => typeMatchesBaseName type' baseName
1394
+ | none => return false
1395
+
1396
+ /--
1397
+ Auxiliary method for field notation. Tries to add `e` as a new argument to `args` or `namedArgs`.
1398
+ This method first finds the parameter with a type of the form `(baseName ...)`.
1399
+ When the parameter is found, if it an explicit one and `args` is big enough, we add `e` to `args`.
1400
+ Otherwise, if there isn't another parameter with the same name, we add `e` to `namedArgs`.
1401
+
1402
+ Remark: `fullName` is the name of the resolved "field" access function. It is used for reporting errors
1403
+ -/
1404
+ private partial def addLValArg (baseName : Name) (fullName : Name) (e : Expr) (args : Array Arg) (namedArgs : Array NamedArg) (f : Expr) (explicit : Bool) :
1405
+ MetaM (Array Arg Γ— Array NamedArg) := do
1406
+ withoutModifyingState <| go f (← inferType f) 0 namedArgs (namedArgs.map (Β·.name)) true
1407
+ where
1408
+ /--
1409
+ * `argIdx` is the position into `args` for the next place an explicit argument can be inserted.
1410
+ * `remainingNamedArgs` keeps track of named arguments that haven't been visited yet,
1411
+ for handling the case where multiple parameters have the same name.
1412
+ * `unusableNamedArgs` keeps track of names that can't be used as named arguments. This is initialized with user-provided named arguments.
1413
+ * `allowNamed` is whether or not to allow using named arguments.
1414
+ Disabled after using `CoeFun` since those parameter names unlikely to be meaningful,
1415
+ and otherwise whether dot notation works or not could feel random.
1416
+ -/
1417
+ go (f fType : Expr) (argIdx : Nat) (remainingNamedArgs : Array NamedArg) (unusableNamedArgs : Array Name) (allowNamed : Bool) := withIncRecDepth do
1418
+ /- Use metavariables (rather than `forallTelescope`) to prevent `coerceToFunction?` from succeeding when multiple instances could apply -/
1419
+ let (xs, bInfos, fType') ← forallMetaTelescope fType
1420
+ let mut argIdx := argIdx
1421
+ let mut remainingNamedArgs := remainingNamedArgs
1422
+ let mut unusableNamedArgs := unusableNamedArgs
1423
+ for x in xs, bInfo in bInfos do
1424
+ let xDecl ← x.mvarId!.getDecl
1425
+ if let some idx := remainingNamedArgs.findFinIdx? (Β·.name == xDecl.userName) then
1426
+ /- If there is named argument with name `xDecl.userName`, then it is accounted for and we can't make use of it. -/
1427
+ remainingNamedArgs := remainingNamedArgs.eraseIdx idx
1428
+ else
1429
+ if ← typeMatchesBaseName xDecl.type baseName then
1430
+ /- We found a type of the form (baseName ...), or we found the first explicit argument in useFirstExplicit mode.
1431
+ First, we check if the current argument is one that can be used positionally,
1432
+ and if the current explicit position "fits" at `args` (i.e., it must be ≀ arg.size) -/
1433
+ if h : argIdx ≀ args.size ∧ (explicit || bInfo.isExplicit) then
1434
+ /- We can insert `e` as an explicit argument -/
1435
+ return (args.insertIdx argIdx (Arg.expr e), namedArgs)
1436
+ else
1437
+ /- If we can't add `e` to `args`, we try to add it using a named argument, but this is only possible
1438
+ if there isn't an argument with the same name occurring before it. -/
1439
+ if !allowNamed || unusableNamedArgs.contains xDecl.userName then
1440
+ throwUnusableParameter allowNamed xDecl
1441
+ else
1442
+ return (args, namedArgs.push { name := xDecl.userName, val := Arg.expr e })
1443
+ /- Advance `argIdx` and update seen named arguments. -/
1444
+ if explicit || bInfo.isExplicit then
1445
+ argIdx := argIdx + 1
1446
+ unusableNamedArgs := unusableNamedArgs.push xDecl.userName
1447
+ /- If named arguments aren't allowed, then it must still be possible to pass the value as an explicit argument.
1448
+ Otherwise, we can abort now. -/
1449
+ if allowNamed || argIdx ≀ args.size then
1450
+ if let fType'@(.forallE ..) ← whnf fType' then
1451
+ return ← go (mkAppN f xs) fType' argIdx remainingNamedArgs unusableNamedArgs allowNamed
1452
+ if let some f' ← coerceToFunction? (mkAppN f xs) then
1453
+ return ← go f' (← inferType f') argIdx remainingNamedArgs unusableNamedArgs false
1454
+ let tyCtorMsg := MessageData.ofLazyM do
1455
+ let some decl := (← getEnv).find? baseName | return .ofConstName baseName
1456
+ if decl.type.isForall then
1457
+ return m!"{.ofConstName baseName} ..."
1458
+ else
1459
+ return .ofConstName baseName
1460
+ throwError m!"Invalid field notation: Function `{.ofConstName fullName}` does not have a usable \
1461
+ parameter of type `{tyCtorMsg}` for which to substitute{inlineExprTrailing e}"
1462
+ ++ .note m!"Such a parameter must be explicit, or implicit with a unique name, to be used by field notation"
1463
+
1464
+ throwUnusableParameter (allowNamed : Bool) (xDecl : MetavarDecl) :=
1465
+ let note : MessageData := if !allowNamed && !xDecl.userName.hasMacroScopes then
1466
+ .note m!"Field notation cannot refer to parameter `{xDecl.userName}` of `{.ofConstName fullName}` \
1467
+ by name because that constant was coerced to a function"
1468
+ else if allowNamed then
1469
+ let param := if xDecl.userName.hasMacroScopes then .nil else m!" `{xDecl.userName}`"
1470
+ .note m!"The parameter{param} of `{.ofConstName fullName}` cannot be referred to by name \
1471
+ because that function has a preceding parameter of the same name"
1472
+ else .nil
1473
+ -- Transforming field notation into direct application is too involved to offer a confident
1474
+ -- concrete edit suggestion here
1475
+ let hint := MessageData.hint' <|
1476
+ m!"Consider rewriting this application without field notation (e.g., `C.f x` instead of `x.f`)" ++
1477
+ if allowNamed then
1478
+ m!" or changing the parameter names of `{.ofConstName fullName}` to avoid this conflict"
1479
+ else .nil
1480
+ throwError m!"Invalid field notation: `{.ofConstName fullName}` has a parameter with \
1481
+ expected type{indentExpr xDecl.type}\nbut it cannot be used" ++ note ++ hint
1482
+
1483
+ /-- Adds the `TermInfo` for the field of a projection. See `Lean.Parser.Term.identProjKind`. -/
1484
+ private def addProjTermInfo
1485
+ (stx : Syntax)
1486
+ (e : Expr)
1487
+ (expectedType? : Option Expr := none)
1488
+ (lctx? : Option LocalContext := none)
1489
+ (elaborator : Name := Name.anonymous)
1490
+ (isBinder force : Bool := false)
1491
+ : TermElabM Expr :=
1492
+ addTermInfo (Syntax.node .none Parser.Term.identProjKind #[stx]) e expectedType? lctx? elaborator isBinder force
1493
+
1494
+ private def elabAppLValsAux (namedArgs : Array NamedArg) (args : Array Arg) (expectedType? : Option Expr) (explicit ellipsis : Bool)
1495
+ (f : Expr) (lvals : List LVal) : TermElabM Expr :=
1496
+ let rec loop : Expr β†’ List LVal β†’ TermElabM Expr
1497
+ | f, [] => elabAppArgs f namedArgs args expectedType? explicit ellipsis
1498
+ | f, lval::lvals => do
1499
+ if let LVal.fieldName (ref := ref) .. := lval then
1500
+ addDotCompletionInfo ref f expectedType?
1501
+ let hasArgs := !namedArgs.isEmpty || !args.isEmpty
1502
+ let (f, lvalRes) ← resolveLVal f lval hasArgs
1503
+ match lvalRes with
1504
+ | LValResolution.projIdx structName idx =>
1505
+ let f ← mkProjAndCheck structName idx f
1506
+ let f ← addTermInfo lval.getRef f
1507
+ loop f lvals
1508
+ | LValResolution.projFn baseStructName structName fieldName =>
1509
+ let f ← mkBaseProjections baseStructName structName f
1510
+ let some info := getFieldInfo? (← getEnv) baseStructName fieldName | unreachable!
1511
+ if isPrivateNameFromImportedModule (← getEnv) info.projFn then
1512
+ throwError "Field `{fieldName}` from structure `{structName}` is private"
1513
+ let projFn ← mkConst info.projFn
1514
+ let projFn ← addProjTermInfo lval.getRef projFn
1515
+ if lvals.isEmpty then
1516
+ let namedArgs ← addNamedArg namedArgs { name := `self, val := Arg.expr f, suppressDeps := true }
1517
+ elabAppArgs projFn namedArgs args expectedType? explicit ellipsis
1518
+ else
1519
+ let f ← elabAppArgs projFn #[{ name := `self, val := Arg.expr f, suppressDeps := true }] #[] (expectedType? := none) (explicit := false) (ellipsis := false)
1520
+ loop f lvals
1521
+ | LValResolution.const baseStructName structName constName =>
1522
+ let f ← if baseStructName != structName then mkBaseProjections baseStructName structName f else pure f
1523
+ let projFn ← mkConst constName
1524
+ let projFn ← addProjTermInfo lval.getRef projFn
1525
+ if lvals.isEmpty then
1526
+ let (args, namedArgs) ← addLValArg baseStructName constName f args namedArgs projFn explicit
1527
+ elabAppArgs projFn namedArgs args expectedType? explicit ellipsis
1528
+ else
1529
+ let (args, namedArgs) ← addLValArg baseStructName constName f #[] #[] projFn (explicit := false)
1530
+ let f ← elabAppArgs projFn namedArgs args (expectedType? := none) (explicit := false) (ellipsis := false)
1531
+ loop f lvals
1532
+ | LValResolution.localRec baseName fullName fvar =>
1533
+ let fvar ← addProjTermInfo lval.getRef fvar
1534
+ if lvals.isEmpty then
1535
+ let (args, namedArgs) ← addLValArg baseName fullName f args namedArgs fvar explicit
1536
+ elabAppArgs fvar namedArgs args expectedType? explicit ellipsis
1537
+ else
1538
+ let (args, namedArgs) ← addLValArg baseName fullName f #[] #[] fvar (explicit := false)
1539
+ let f ← elabAppArgs fvar namedArgs args (expectedType? := none) (explicit := false) (ellipsis := false)
1540
+ loop f lvals
1541
+ loop f lvals
1542
+
1543
+ private def elabAppLVals (f : Expr) (lvals : List LVal) (namedArgs : Array NamedArg) (args : Array Arg)
1544
+ (expectedType? : Option Expr) (explicit ellipsis : Bool) : TermElabM Expr := do
1545
+ elabAppLValsAux namedArgs args expectedType? explicit ellipsis f lvals
1546
+
1547
+ def elabExplicitUnivs (lvls : Array Syntax) : TermElabM (List Level) := do
1548
+ lvls.foldrM (init := []) fun stx lvls => return (← elabLevel stx)::lvls
1549
+
1550
+ /-!
1551
+ # Interaction between `errToSorry` and `observing`.
1552
+
1553
+ - The method `elabTerm` catches exceptions, logs them, and returns a synthetic sorry (IF `ctx.errToSorry` == true).
1554
+
1555
+ - When we elaborate choice nodes (and overloaded identifiers), we track multiple results using the `observing x` combinator.
1556
+ The `observing x` executes `x` and returns a `TermElabResult`.
1557
+
1558
+ `observing x` does not check for synthetic sorry's, just an exception. Thus, it may think `x` worked when it didn't
1559
+ if a synthetic sorry was introduced. We decided that checking for synthetic sorrys at `observing` is not a good solution
1560
+ because it would not be clear to decide what the "main" error message for the alternative is. When the result contains
1561
+ a synthetic `sorry`, it is not clear which error message corresponds to the `sorry`. Moreover, while executing `x`, many
1562
+ error messages may have been logged. Recall that we need an error per alternative at `mergeFailures`.
1563
+
1564
+ Thus, we decided to set `errToSorry` to `false` whenever processing choice nodes and overloaded symbols.
1565
+
1566
+ Important: we rely on the property that after `errToSorry` is set to
1567
+ false, no elaboration function executed by `x` will reset it to
1568
+ `true`.
1569
+ -/
1570
+
1571
+ private partial def elabAppFnId (fIdent : Syntax) (fExplicitUnivs : List Level) (lvals : List LVal)
1572
+ (namedArgs : Array NamedArg) (args : Array Arg) (expectedType? : Option Expr) (explicit ellipsis overloaded : Bool) (acc : Array (TermElabResult Expr))
1573
+ : TermElabM (Array (TermElabResult Expr)) := do
1574
+ let funLVals ← withRef fIdent <| resolveName' fIdent fExplicitUnivs expectedType?
1575
+ let overloaded := overloaded || funLVals.length > 1
1576
+ -- Set `errToSorry` to `false` if `funLVals` > 1. See comment above about the interaction between `errToSorry` and `observing`.
1577
+ withReader (fun ctx => { ctx with errToSorry := funLVals.length == 1 && ctx.errToSorry }) do
1578
+ funLVals.foldlM (init := acc) fun acc (f, fIdent, fields) => do
1579
+ let lvals' := toLVals fields (first := true)
1580
+ let s ← observing do
1581
+ checkDeprecated fIdent f
1582
+ let f ← addTermInfo fIdent f expectedType?
1583
+ let e ← elabAppLVals f (lvals' ++ lvals) namedArgs args expectedType? explicit ellipsis
1584
+ if overloaded then ensureHasType expectedType? e else return e
1585
+ return acc.push s
1586
+ where
1587
+ toName (fields : List Syntax) : Name :=
1588
+ let rec go
1589
+ | [] => .anonymous
1590
+ | field :: fields => .mkStr (go fields) field.getId.toString
1591
+ go fields.reverse
1592
+
1593
+ toLVals : List Syntax β†’ (first : Bool) β†’ List LVal
1594
+ | [], _ => []
1595
+ | field::fields, true => .fieldName field field.getId.getString! (toName (field::fields)) fIdent :: toLVals fields false
1596
+ | field::fields, false => .fieldName field field.getId.getString! none fIdent :: toLVals fields false
1597
+
1598
+ /-- Resolve `(.$id:ident)` using the expected type to infer namespace. -/
1599
+ private partial def resolveDotName (id : Syntax) (expectedType? : Option Expr) : TermElabM Expr := do
1600
+ tryPostponeIfNoneOrMVar expectedType?
1601
+ let some expectedType := expectedType?
1602
+ | throwError "Invalid dotted identifier notation: Could not determine the expected type of `.{id}`"
1603
+ withForallBody expectedType fun resultType => do
1604
+ go resultType expectedType #[]
1605
+ where
1606
+ /-- A weak version of forallTelescopeReducing that only uses whnfCore, to avoid unfolding definitions except by `unfoldDefinition?` below. -/
1607
+ withForallBody {Ξ±} (type : Expr) (k : Expr β†’ TermElabM Ξ±) : TermElabM Ξ± :=
1608
+ forallTelescope type fun _ body => do
1609
+ let body ← whnfCore body
1610
+ if body.isForall then
1611
+ withForallBody body k
1612
+ else
1613
+ k body
1614
+ go (resultType : Expr) (expectedType : Expr) (previousExceptions : Array Exception) : TermElabM Expr := do
1615
+ let resultType ← instantiateMVars resultType
1616
+ let resultTypeFn := resultType.cleanupAnnotations.getAppFn
1617
+ try
1618
+ tryPostponeIfMVar resultTypeFn
1619
+ match resultTypeFn.cleanupAnnotations with
1620
+ | .const declName .. =>
1621
+ let idNew := declName ++ id.getId.eraseMacroScopes
1622
+ if (← getEnv).contains idNew then
1623
+ mkConst idNew
1624
+ else if let some (fvar, []) ← resolveLocalName idNew then
1625
+ return fvar
1626
+ else
1627
+ throwUnknownIdentifierAt id <| m!"Unknown identifier `{idNew}`"
1628
+ ++ .note m!"Inferred this identifier from the expected type of `.{id}`:{indentExpr expectedType}"
1629
+ | .sort .. =>
1630
+ throwNamedError lean.invalidDottedIdent "Invalid dotted identifier notation: Not supported on type universe{indentExpr resultTypeFn}"
1631
+ | _ =>
1632
+ if expectedType.getAppFn.isMVar then
1633
+ throwNamedError lean.invalidDottedIdent "Invalid dotted identifier notation: The expected type of `.{id}` could not be determined"
1634
+ else
1635
+ throwNamedError lean.invalidDottedIdent "Invalid dotted identifier notation: The expected type of `.{id}`{indentExpr expectedType}\n\
1636
+ is not of the form `C ...` or `... β†’ C ...` where C is a constant"
1637
+ catch
1638
+ | ex@(.error ..) =>
1639
+ match (← unfoldDefinition? resultType) with
1640
+ | some resultType =>
1641
+ withForallBody resultType fun resultType => do
1642
+ go resultType expectedType (previousExceptions.push ex)
1643
+ | none =>
1644
+ previousExceptions.forM fun ex => logException ex
1645
+ throw ex
1646
+ | ex@(.internal _ _) => throw ex
1647
+
1648
+ private partial def elabAppFn (f : Syntax) (lvals : List LVal) (namedArgs : Array NamedArg) (args : Array Arg)
1649
+ (expectedType? : Option Expr) (explicit ellipsis overloaded : Bool) (acc : Array (TermElabResult Expr)) : TermElabM (Array (TermElabResult Expr)) := do
1650
+ if f.getKind == choiceKind then
1651
+ -- Set `errToSorry` to `false` when processing choice nodes. See comment above about the interaction between `errToSorry` and `observing`.
1652
+ withReader (fun ctx => { ctx with errToSorry := false }) do
1653
+ f.getArgs.foldlM (init := acc) fun acc f => elabAppFn f lvals namedArgs args expectedType? explicit ellipsis true acc
1654
+ else
1655
+ let elabFieldName (e field : Syntax) (explicit : Bool) := do
1656
+ let newLVals := field.identComponents.map fun comp =>
1657
+ -- We use `none` in `suffix?` since `field` can't be part of a composite name
1658
+ LVal.fieldName comp comp.getId.getString! none f
1659
+ elabAppFn e (newLVals ++ lvals) namedArgs args expectedType? explicit ellipsis overloaded acc
1660
+ let elabFieldIdx (e idxStx : Syntax) (explicit : Bool) := do
1661
+ let some idx := idxStx.isFieldIdx?
1662
+ | throwError "Internal error: Unexpected field index syntax `{idxStx}`"
1663
+ elabAppFn e (LVal.fieldIdx idxStx idx :: lvals) namedArgs args expectedType? explicit ellipsis overloaded acc
1664
+ match f with
1665
+ | `($(e).$idx:fieldIdx) => elabFieldIdx e idx explicit
1666
+ | `($e |>.$idx:fieldIdx) => elabFieldIdx e idx explicit
1667
+ | `($(e).$field:ident) => elabFieldName e field explicit
1668
+ | `($e |>.$field:ident) => elabFieldName e field explicit
1669
+ | `(@$(e).$idx:fieldIdx) => elabFieldIdx e idx (explicit := true)
1670
+ | `(@$(e).$field:ident) => elabFieldName e field (explicit := true)
1671
+ | `($_:ident@$_:term) =>
1672
+ throwError m!"Expected a function, but found the named pattern{indentD f}"
1673
+ ++ .note m!"Named patterns `<identifier>@<term>` can only be used when pattern-matching"
1674
+ | `($id:ident) => do
1675
+ elabAppFnId id [] lvals namedArgs args expectedType? explicit ellipsis overloaded acc
1676
+ | `($id:ident.{$us,*}) => do
1677
+ let us ← elabExplicitUnivs us
1678
+ elabAppFnId id us lvals namedArgs args expectedType? explicit ellipsis overloaded acc
1679
+ | `(@$id:ident) =>
1680
+ elabAppFn id lvals namedArgs args expectedType? (explicit := true) ellipsis overloaded acc
1681
+ | `(@$_:ident.{$_us,*}) =>
1682
+ elabAppFn (f.getArg 1) lvals namedArgs args expectedType? (explicit := true) ellipsis overloaded acc
1683
+ | `(@$_) => throwUnsupportedSyntax -- invalid occurrence of `@`
1684
+ | `(_) => throwError "A placeholder `_` cannot be used where a function is expected"
1685
+ | `(.$id:ident) =>
1686
+ addCompletionInfo <| CompletionInfo.dotId id id.getId (← getLCtx) expectedType?
1687
+ let fConst ← resolveDotName id expectedType?
1688
+ let s ← observing do
1689
+ -- Use (force := true) because we want to record the result of .ident resolution even in patterns
1690
+ let fConst ← addTermInfo f fConst expectedType? (force := true)
1691
+ let e ← elabAppLVals fConst lvals namedArgs args expectedType? explicit ellipsis
1692
+ if overloaded then ensureHasType expectedType? e else return e
1693
+ return acc.push s
1694
+ | _ => do
1695
+ let catchPostpone := !overloaded
1696
+ /- If we are processing a choice node, then we should use `catchPostpone == false` when elaborating terms.
1697
+ Recall that `observing` does not catch `postponeExceptionId`. -/
1698
+ if lvals.isEmpty && namedArgs.isEmpty && args.isEmpty then
1699
+ /- Recall that elabAppFn is used for elaborating atomics terms **and** choice nodes that may contain
1700
+ arbitrary terms. If they are not being used as a function, we should elaborate using the expectedType. -/
1701
+ let s ← observing do
1702
+ if overloaded then
1703
+ elabTermEnsuringType f expectedType? catchPostpone
1704
+ else
1705
+ elabTerm f expectedType?
1706
+ return acc.push s
1707
+ else
1708
+ let s ← observing do
1709
+ let f ← elabTerm f none catchPostpone
1710
+ let e ← elabAppLVals f lvals namedArgs args expectedType? explicit ellipsis
1711
+ if overloaded then ensureHasType expectedType? e else return e
1712
+ return acc.push s
1713
+
1714
+ /-- Return the successful candidates. Recall we have Syntax `choice` nodes and overloaded symbols when we open multiple namespaces. -/
1715
+ private def getSuccesses (candidates : Array (TermElabResult Expr)) : TermElabM (Array (TermElabResult Expr)) := do
1716
+ let r₁ := candidates.filter fun | EStateM.Result.ok .. => true | _ => false
1717
+ if r₁.size ≀ 1 then return r₁
1718
+ let rβ‚‚ ← candidates.filterM fun
1719
+ | .ok e s => do
1720
+ if e.isMVar then
1721
+ /- Make sure `e` is not a delayed coercion.
1722
+ Recall that coercion insertion may be delayed when the type and expected type contains
1723
+ metavariables that block TC resolution.
1724
+ When processing overloaded notation, we disallow delayed coercions at `e`. -/
1725
+ try
1726
+ s.restore
1727
+ synthesizeSyntheticMVars -- Tries to process pending coercions (and elaboration tasks)
1728
+ let e ← instantiateMVars e
1729
+ if e.isMVar then
1730
+ /- If `e` is still a metavariable, and its `SyntheticMVarDecl` is a coercion, we discard this solution -/
1731
+ if let some synDecl ← getSyntheticMVarDecl? e.mvarId! then
1732
+ if synDecl.kind matches SyntheticMVarKind.coe .. then
1733
+ return false
1734
+ catch _ =>
1735
+ -- If `synthesizeSyntheticMVars` failed, we just eliminate the candidate.
1736
+ return false
1737
+ return true
1738
+ | _ => return false
1739
+ if rβ‚‚.size == 0 then
1740
+ return r₁
1741
+ if rβ‚‚.size == 1 then
1742
+ return rβ‚‚
1743
+ /-
1744
+ If there are still more than one solution, discard solutions that have pending metavariables.
1745
+ We added this extra filter to address regressions introduced after fixing
1746
+ `isDefEqStuckEx` behavior at `ExprDefEq.lean`.
1747
+ -/
1748
+ let rβ‚‚ ← candidates.filterM fun
1749
+ | .ok _ s => do
1750
+ try
1751
+ s.restore
1752
+ synthesizeSyntheticMVars (postpone := .no)
1753
+ return true
1754
+ catch _ =>
1755
+ return false
1756
+ | _ => return false
1757
+ if rβ‚‚.size == 0 then
1758
+ return r₁
1759
+ return rβ‚‚
1760
+ /--
1761
+ Throw an error message that describes why each possible interpretation for the overloaded notation and symbols did not work.
1762
+ We use a nested error message to aggregate the exceptions produced by each failure.
1763
+ -/
1764
+ private def mergeFailures (failures : Array (TermElabResult Expr)) : TermElabM Ξ± := do
1765
+ let exs := failures.map fun | .error ex _ => ex | _ => unreachable!
1766
+ let trees := failures.map (fun | .error _ s => s.meta.core.infoState.trees | _ => unreachable!)
1767
+ |>.filterMap (Β·[0]?)
1768
+ -- Retain partial `InfoTree` subtrees in an `.ofChoiceInfo` node in case of multiple failures.
1769
+ -- This ensures that the language server still has `Info` to work with when multiple overloaded
1770
+ -- elaborators fail.
1771
+ withInfoContext (mkInfo := pure <| .ofChoiceInfo { elaborator := .anonymous, stx := ← getRef }) do
1772
+ for tree in trees do
1773
+ pushInfoTree tree
1774
+ throwErrorWithNestedErrors "overloaded" exs
1775
+
1776
+ private def elabAppAux (f : Syntax) (namedArgs : Array NamedArg) (args : Array Arg) (ellipsis : Bool) (expectedType? : Option Expr) : TermElabM Expr := do
1777
+ let candidates ← elabAppFn f [] namedArgs args expectedType? (explicit := false) (ellipsis := ellipsis) (overloaded := false) #[]
1778
+ if h : candidates.size = 1 then
1779
+ have : 0 < candidates.size := by rw [h]; decide
1780
+ applyResult candidates[0]
1781
+ else
1782
+ let successes ← getSuccesses candidates
1783
+ if h : successes.size = 1 then
1784
+ have : 0 < successes.size := by rw [h]; decide
1785
+ applyResult successes[0]
1786
+ else if successes.size > 1 then
1787
+ let msgs : Array MessageData ← successes.mapM fun success => do
1788
+ match success with
1789
+ | .ok e s => withMCtx s.meta.meta.mctx <| withEnv s.meta.core.env do addMessageContext m!"{e} : {← inferType e}"
1790
+ | _ => unreachable!
1791
+ throwErrorAt f "Ambiguous term{indentD f}\nPossible interpretations:{toMessageList msgs}"
1792
+ else
1793
+ withRef f <| mergeFailures candidates
1794
+
1795
+ /--
1796
+ We annotate recursive applications with their `Syntax` node to make sure we can produce error messages with
1797
+ correct position information at `WF` and `Structural`.
1798
+ -/
1799
+ -- TODO: It is overkill to store the whole `Syntax` object, and we have to make sure we erase it later.
1800
+ -- We should store only the position information in the future.
1801
+ -- Recall that we will need to have a compact way of storing position information in the future anyway, if we
1802
+ -- want to support debugging information
1803
+ private def annotateIfRec (stx : Syntax) (e : Expr) : TermElabM Expr := do
1804
+ if (← read).saveRecAppSyntax then
1805
+ let resultFn := e.getAppFn
1806
+ if resultFn.isFVar then
1807
+ let localDecl ← resultFn.fvarId!.getDecl
1808
+ if localDecl.isAuxDecl then
1809
+ return mkRecAppWithSyntax e stx
1810
+ return e
1811
+
1812
+ @[builtin_term_elab app] def elabApp : TermElab := fun stx expectedType? =>
1813
+ universeConstraintsCheckpoint do
1814
+ let (f, namedArgs, args, ellipsis) ← expandApp stx
1815
+ annotateIfRec stx (← elabAppAux f namedArgs args (ellipsis := ellipsis) expectedType?)
1816
+
1817
+ private def elabAtom : TermElab := fun stx expectedType? => do
1818
+ annotateIfRec stx (← elabAppAux stx #[] #[] (ellipsis := false) expectedType?)
1819
+
1820
+ @[builtin_term_elab ident] def elabIdent : TermElab := elabAtom
1821
+ @[builtin_term_elab namedPattern] def elabNamedPattern : TermElab := elabAtom
1822
+ @[builtin_term_elab dotIdent] def elabDotIdent : TermElab := elabAtom
1823
+ @[builtin_term_elab explicitUniv] def elabExplicitUniv : TermElab := elabAtom
1824
+ @[builtin_term_elab pipeProj] def elabPipeProj : TermElab
1825
+ | `($e |>.%$tk$f $args*), expectedType? =>
1826
+ universeConstraintsCheckpoint do
1827
+ let (namedArgs, args, ellipsis) ← expandArgs args
1828
+ let mut stx ← `($e |>.%$tk$f)
1829
+ if let (some startPos, some stopPos) := (e.raw.getPos?, f.raw.getTailPos?) then
1830
+ stx := ⟨stx.raw.setInfo <| .synthetic (canonical := true) startPos stopPos⟩
1831
+ elabAppAux stx namedArgs args (ellipsis := ellipsis) expectedType?
1832
+ | _, _ => throwUnsupportedSyntax
1833
+
1834
+ @[builtin_term_elab explicit] def elabExplicit : TermElab := fun stx expectedType? =>
1835
+ match stx with
1836
+ | `(@$_:ident) => elabAtom stx expectedType? -- Recall that `elabApp` also has support for `@`
1837
+ | `(@$_:ident.{$_us,*}) => elabAtom stx expectedType?
1838
+ | `(@$(_).$_:fieldIdx) => elabAtom stx expectedType?
1839
+ | `(@$(_).$_:ident) => elabAtom stx expectedType?
1840
+ | `(@($t)) => elabTerm t expectedType? (implicitLambda := false) -- `@` is being used just to disable implicit lambdas
1841
+ | `(@$t) => elabTerm t expectedType? (implicitLambda := false) -- `@` is being used just to disable implicit lambdas
1842
+ | _ => throwUnsupportedSyntax
1843
+
1844
+ @[builtin_term_elab choice] def elabChoice : TermElab := elabAtom
1845
+ @[builtin_term_elab proj] def elabProj : TermElab := elabAtom
1846
+
1847
+ builtin_initialize
1848
+ registerTraceClass `Elab.app
1849
+ registerTraceClass `Elab.app.args (inherited := true)
1850
+ registerTraceClass `Elab.app.propagateExpectedType (inherited := true)
1851
+ registerTraceClass `Elab.app.finalize (inherited := true)
1852
+ registerTraceClass `Elab.app.elab_as_elim (inherited := true)
1853
+
1854
+ end Lean.Elab.Term
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Arg.lean ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Term
8
+
9
+ namespace Lean.Elab.Term
10
+
11
+ /--
12
+ Auxiliary inductive datatype for combining unelaborated syntax
13
+ and already elaborated expressions. It is used to elaborate applications.
14
+ -/
15
+ inductive Arg where
16
+ | stx (val : Syntax)
17
+ | expr (val : Expr)
18
+ deriving Inhabited
19
+
20
+ /-- Named arguments created using the notation `(x := val)`. -/
21
+ structure NamedArg where
22
+ ref : Syntax := Syntax.missing
23
+ name : Name
24
+ val : Arg
25
+ /-- If `true`, then make all parameters that depend on this one become implicit.
26
+ This is used for projection notation, since structure parameters might be explicit for classes. -/
27
+ suppressDeps : Bool := false
28
+ deriving Inhabited
29
+
30
+ instance : ToMessageData Arg where
31
+ toMessageData
32
+ | .stx stx => toMessageData stx
33
+ | .expr e => toMessageData e
34
+
35
+ /--
36
+ Add a new named argument to `namedArgs`, and throw an error if it already contains a named argument
37
+ with the same name. -/
38
+ def addNamedArg (namedArgs : Array NamedArg) (namedArg : NamedArg) : MetaM (Array NamedArg) := do
39
+ if namedArgs.any (namedArg.name == Β·.name) then
40
+ throwError "argument '{namedArg.name}' was already set"
41
+ return namedArgs.push namedArg
42
+
43
+ partial def expandArgs (args : Array Syntax) : MetaM (Array NamedArg Γ— Array Arg Γ— Bool) := do
44
+ let (args, ellipsis) :=
45
+ if args.isEmpty then
46
+ (args, false)
47
+ else if args.back!.isOfKind ``Lean.Parser.Term.ellipsis then
48
+ (args.pop, true)
49
+ else
50
+ (args, false)
51
+ let (namedArgs, args) ← args.foldlM (init := (#[], #[])) fun (namedArgs, args) stx => do
52
+ if stx.getKind == ``Lean.Parser.Term.namedArgument then
53
+ -- trailing_tparser try ("(" >> ident >> " := ") >> termParser >> ")"
54
+ let name := stx[1].getId.eraseMacroScopes
55
+ let val := stx[3]
56
+ let namedArgs ← addNamedArg namedArgs { ref := stx, name := name, val := Arg.stx val }
57
+ return (namedArgs, args)
58
+ else if stx.getKind == ``Lean.Parser.Term.ellipsis then
59
+ throwErrorAt stx "unexpected '..'"
60
+ else
61
+ return (namedArgs, args.push $ Arg.stx stx)
62
+ return (namedArgs, args, ellipsis)
63
+
64
+ def expandApp (stx : Syntax) : MetaM (Syntax Γ— Array NamedArg Γ— Array Arg Γ— Bool) := do
65
+ let (namedArgs, args, ellipsis) ← expandArgs stx[1].getArgs
66
+ return (stx[0], namedArgs, args, ellipsis)
67
+
68
+ end Lean.Elab.Term
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Attributes.lean ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2020 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Sebastian Ullrich
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Util
8
+ namespace Lean.Elab
9
+
10
+ structure Attribute where
11
+ kind : AttributeKind := AttributeKind.global
12
+ name : Name
13
+ stx : Syntax := Syntax.missing
14
+ deriving Inhabited
15
+
16
+ instance : ToFormat Attribute where
17
+ format attr :=
18
+ let kindStr := match attr.kind with
19
+ | AttributeKind.global => ""
20
+ | AttributeKind.local => "local "
21
+ | AttributeKind.scoped => "scoped "
22
+ Format.bracket "@[" f!"{kindStr}{attr.name}{toString attr.stx}" "]"
23
+
24
+ /--
25
+ ```
26
+ attrKind := leading_parser optional (Β«scopedΒ» <|> Β«localΒ»)
27
+ ```
28
+ -/
29
+ def toAttributeKind (attrKindStx : Syntax) : MacroM AttributeKind := do
30
+ if attrKindStx[0].isNone then
31
+ return AttributeKind.global
32
+ else if attrKindStx[0][0].getKind == ``Lean.Parser.Term.scoped then
33
+ if (← Macro.getCurrNamespace).isAnonymous then
34
+ throw <| Macro.Exception.error (← getRef) "scoped attributes must be used inside namespaces"
35
+ return AttributeKind.scoped
36
+ else
37
+ return AttributeKind.local
38
+
39
+ def mkAttrKindGlobal : Syntax :=
40
+ mkNode ``Lean.Parser.Term.attrKind #[mkNullNode]
41
+
42
+ def elabAttr [Monad m] [MonadEnv m] [MonadResolveName m] [MonadError m] [MonadMacroAdapter m] [MonadRecDepth m] [MonadTrace m] [MonadOptions m] [AddMessageContext m] [MonadLiftT IO m] (attrInstance : Syntax) : m Attribute := do
43
+ /- attrInstance := ppGroup $ leading_parser attrKind >> attrParser -/
44
+ let attrKind ← liftMacroM <| toAttributeKind attrInstance[0]
45
+ let attr := attrInstance[1]
46
+ let attr ← liftMacroM <| expandMacros attr
47
+ let attrName ← if attr.getKind == ``Parser.Attr.simple then
48
+ pure attr[0].getId.eraseMacroScopes
49
+ else match attr.getKind with
50
+ | .str _ s => pure <| Name.mkSimple s
51
+ | _ => throwErrorAt attr "unknown attribute"
52
+ let .ok _impl := getAttributeImpl (← getEnv) attrName
53
+ | throwError "unknown attribute [{attrName}]"
54
+ /- The `AttrM` does not have sufficient information for expanding macros in `args`.
55
+ So, we expand them before here before we invoke the attributer handlers implemented using `AttrM`. -/
56
+ return { kind := attrKind, name := attrName, stx := attr }
57
+
58
+ def elabAttrs [Monad m] [MonadEnv m] [MonadResolveName m] [MonadError m] [MonadMacroAdapter m] [MonadRecDepth m] [MonadTrace m] [MonadOptions m] [AddMessageContext m] [MonadLog m] [MonadLiftT IO m] (attrInstances : Array Syntax) : m (Array Attribute) := do
59
+ let mut attrs := #[]
60
+ for attr in attrInstances do
61
+ try
62
+ attrs := attrs.push (← withRef attr do elabAttr attr)
63
+ catch ex =>
64
+ logException ex
65
+ return attrs
66
+
67
+ -- leading_parser "@[" >> sepBy1 attrInstance ", " >> "]"
68
+ def elabDeclAttrs [Monad m] [MonadEnv m] [MonadResolveName m] [MonadError m] [MonadMacroAdapter m] [MonadRecDepth m] [MonadTrace m] [MonadOptions m] [AddMessageContext m] [MonadLog m] [MonadLiftT IO m] (stx : Syntax) : m (Array Attribute) :=
69
+ elabAttrs stx[1].getSepArgs
70
+
71
+ end Lean.Elab
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/AutoBound.lean ADDED
@@ -0,0 +1,51 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2020 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Data.Options
8
+
9
+ /-! # Basic support for auto bound implicit local names -/
10
+
11
+ namespace Lean.Elab
12
+
13
+ register_builtin_option autoImplicit : Bool := {
14
+ defValue := true
15
+ descr := "Unbound local variables in declaration headers become implicit arguments. In \"relaxed\" mode (default), any atomic identifier is eligible, otherwise only single character followed by numeric digits are eligible. For example, `def f (x : Vector Ξ± n) : Vector Ξ± n :=` automatically introduces the implicit variables {Ξ± n}."
16
+ }
17
+
18
+ register_builtin_option relaxedAutoImplicit : Bool := {
19
+ defValue := true
20
+ descr := "When \"relaxed\" mode is enabled, any atomic nonempty identifier is eligible for auto bound implicit locals (see option `autoImplicit`)."
21
+ }
22
+
23
+
24
+ private def isValidAutoBoundSuffix (s : String) : Bool :=
25
+ s.toSubstring.drop 1 |>.all fun c => c.isDigit || isSubScriptAlnum c || c == '_' || c == '\''
26
+
27
+ /-!
28
+ Remark: Issue #255 exposed a nasty interaction between macro scopes and auto-bound-implicit names.
29
+ ```
30
+ local notation "A" => id x
31
+ theorem test : A = A := sorry
32
+ ```
33
+ We used to use `n.eraseMacroScopes` at `isValidAutoBoundImplicitName` and `isValidAutoBoundLevelName`.
34
+ Thus, in the example above, when `A` is expanded, a `x` with a fresh macro scope is created.
35
+ `x`+macros-scope is not in scope and is a valid auto-bound implicit name after macro scopes are erased.
36
+ So, an auto-bound exception would be thrown, and `x`+macro-scope would be added as a new implicit.
37
+ When, we try again, a `x` with a new macro scope is created and this process keeps repeating.
38
+ Therefore, we do consider identifier with macro scopes anymore.
39
+ -/
40
+
41
+ def isValidAutoBoundImplicitName (n : Name) (relaxed : Bool) : Bool :=
42
+ match n with
43
+ | .str .anonymous s => s.length > 0 && (relaxed || isValidAutoBoundSuffix s)
44
+ | _ => false
45
+
46
+ def isValidAutoBoundLevelName (n : Name) (relaxed : Bool) : Bool :=
47
+ match n with
48
+ | .str .anonymous s => s.length > 0 && (relaxed || (s.front.isLower && isValidAutoBoundSuffix s))
49
+ | _ => false
50
+
51
+ end Lean.Elab
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/AuxDef.lean ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Gabriel Ebner
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Command
8
+
9
+ namespace Lean.Elab.Command
10
+ open Lean.Parser.Command
11
+ open Lean.Parser.Term
12
+
13
+ /--
14
+ Declares an auxiliary definition with an automatically generated name.
15
+ For example, `aux_def foo : Nat := 42` creates a definition
16
+ with an internal, unused name based on the suggestion `foo`.
17
+ -/
18
+ scoped syntax (name := aux_def) docComment ? attributes ? "aux_def" ident+ ":" term ":=" term : command
19
+
20
+ @[builtin_command_elab Β«aux_defΒ»]
21
+ def elabAuxDef : CommandElab
22
+ | `($[$doc?:docComment]? $[$attrs?:attributes]? aux_def $suggestion* : $ty := $body) => do
23
+ let id := suggestion.map (Β·.getId.eraseMacroScopes) |>.foldl (Β· ++ Β·) Name.anonymous
24
+ let id := `_aux ++ (← getMainModule) ++ `_ ++ id
25
+ let id := String.intercalate "_" <| id.components.map (Β·.toString (escape := false))
26
+ let ns ← getCurrNamespace
27
+ -- We use a new generator here because we want more control over the name; the default would
28
+ -- create a private name that then breaks the macro below. We assume that `aux_def` is not used
29
+ -- with the same arguments in parallel contexts.
30
+ let env := (← getEnv).setExporting true
31
+ let (id, _) := { namePrefix := ns : DeclNameGenerator }.mkUniqueName env (Β«infixΒ» := Name.mkSimple id)
32
+ let id := id.replacePrefix ns Name.anonymous -- TODO: replace with def _root_.id
33
+ elabCommand <|
34
+ ← `($[$doc?:docComment]? $[$attrs?:attributes]?
35
+ meta def $(mkIdentFrom (mkNullNode suggestion) id (canonical := true)):ident : $ty := $body)
36
+ | _ => throwUnsupportedSyntax
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/BinderPredicates.lean ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Gabriel Ebner
5
+ -/
6
+ prelude
7
+ import Init.BinderPredicates
8
+ import Lean.Parser.Syntax
9
+ import Lean.Elab.MacroArgUtil
10
+ import Lean.Linter.MissingDocs
11
+
12
+ namespace Lean.Elab.Command
13
+
14
+ @[builtin_command_elab binderPredicate] def elabBinderPred : CommandElab := fun stx => do
15
+ match stx with
16
+ | `($[$doc?:docComment]? $[@[$attrs?,*]]? $attrKind:attrKind binder_predicate%$tk
17
+ $[(name := $name?)]? $[(priority := $prio?)]? $x $args:macroArg* => $rhs) => do
18
+ let prio ← liftMacroM do evalOptPrio prio?
19
+ let (stxParts, patArgs) := (← args.mapM expandMacroArg).unzip
20
+ let name ← match name? with
21
+ | some name => pure name.getId
22
+ | none => liftMacroM do mkNameFromParserSyntax `binderTerm (mkNullNode stxParts)
23
+ let nameTk := name?.getD (mkIdentFrom tk name)
24
+ /- The command `syntax [<kind>] ...` adds the current namespace to the syntax node kind.
25
+ So, we must include current namespace when we create a pattern for the following
26
+ `macro_rules` commands. -/
27
+ let pat : TSyntax `binderPred := ⟨(mkNode ((← getCurrNamespace) ++ name) patArgs).1⟩
28
+ elabCommand <|<-
29
+ `($[$doc?:docComment]? $[@[$attrs?,*]]? $attrKind:attrKind syntax%$tk
30
+ (name := $nameTk) (priority := $(quote prio)) $[$stxParts]* : binderPred
31
+ $[$doc?:docComment]? macro_rules%$tk
32
+ | `(satisfies_binder_pred% $$($x):term $pat:binderPred) => $rhs)
33
+ | _ => throwUnsupportedSyntax
34
+
35
+ open Linter.MissingDocs Parser Term in
36
+ /-- Missing docs handler for `binder_predicate` -/
37
+ @[builtin_missing_docs_handler Lean.Parser.Command.binderPredicate]
38
+ def checkBinderPredicate : SimpleHandler := fun stx => do
39
+ if stx[0].isNone && stx[2][0][0].getKind != ``Β«localΒ» then
40
+ if stx[4].isNone then lint stx[3] "binder predicate"
41
+ else lintNamed stx[4][0][3] "binder predicate"
42
+
43
+ end Lean.Elab.Command
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Binders.lean ADDED
@@ -0,0 +1,957 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2019 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Quotation.Precheck
8
+ import Lean.Elab.Term
9
+ import Lean.Elab.BindersUtil
10
+ import Lean.Elab.SyntheticMVars
11
+ import Lean.Elab.PreDefinition.TerminationHint
12
+ import Lean.Elab.Match
13
+ import Lean.Compiler.MetaAttr
14
+
15
+ namespace Lean.Elab.Term
16
+ open Meta
17
+ open Lean.Parser.Term
18
+ open TSyntax.Compat
19
+
20
+ /--
21
+ Given syntax of the forms
22
+ a) (`:` term)?
23
+ b) `:` term
24
+ return `term` if it is present, or a hole if not. -/
25
+ private def expandBinderType (ref : Syntax) (stx : Syntax) : Syntax :=
26
+ if stx.getNumArgs == 0 then
27
+ mkHole ref
28
+ else
29
+ stx[1]
30
+
31
+ /-- Given syntax of the form `ident <|> hole`, return `ident`. If `hole`, then we create a new anonymous name. -/
32
+ private def expandBinderIdent (stx : Syntax) : TermElabM Syntax :=
33
+ match stx with
34
+ | `(_) => mkFreshIdent stx (canonical := true)
35
+ | _ => pure stx
36
+
37
+ /-- Given syntax of the form `(ident >> " : ")?`, return `ident`, or a new instance name. -/
38
+ private def expandOptIdent (stx : Syntax) : TermElabM Syntax := do
39
+ if stx.isNone then
40
+ let id ← withFreshMacroScope <| MonadQuotation.addMacroScope `inst
41
+ return mkIdentFrom stx id
42
+ else
43
+ return stx[0]
44
+
45
+ /-- Auxiliary datatype for elaborating binders. -/
46
+ structure BinderView where
47
+ /--
48
+ Position information provider for the Info Tree.
49
+ We currently do not track binder "macro expansion" steps in the info tree.
50
+ For example, suppose we expand a `_` into a fresh identifier. The fresh identifier
51
+ has synthetic position since it was not written by the user, and we would not get
52
+ hover information for the `_` because we also don't have this macro expansion step
53
+ stored in the info tree. Thus, we store the original `Syntax` in `ref`, and use
54
+ it when storing the binder information in the info tree.
55
+
56
+ Potential better solution: add a binder syntax category, an extensible `elabBinder`
57
+ (like we have `elabTerm`), and perform all macro expansion steps at `elabBinder` and
58
+ record them in the infro tree.
59
+ -/
60
+ ref : Syntax
61
+ id : Syntax
62
+ type : Syntax
63
+ bi : BinderInfo
64
+
65
+ /--
66
+ Determines the local declaration kind depending on the variable name.
67
+
68
+ The `__x` in `let __x := 42; body` gets kind `.implDetail`.
69
+ -/
70
+ def kindOfBinderName (binderName : Name) : LocalDeclKind :=
71
+ if binderName.isImplementationDetail then
72
+ .implDetail
73
+ else
74
+ .default
75
+
76
+ partial def quoteAutoTactic : Syntax β†’ CoreM Expr
77
+ | .ident _ _ val preresolved =>
78
+ return mkApp4 (.const ``Syntax.ident [])
79
+ (.const ``SourceInfo.none [])
80
+ (.app (.const ``String.toSubstring []) (mkStrLit (toString val)))
81
+ (toExpr val)
82
+ (toExpr preresolved)
83
+ | stx@(.node _ k args) => do
84
+ if stx.isAntiquot then
85
+ throwErrorAt stx "invalid auto tactic, antiquotation is not allowed"
86
+ else
87
+ let ty := .const ``Syntax []
88
+ let mut quotedArgs := mkApp (.const ``Array.empty [.zero]) ty
89
+ for arg in args do
90
+ if k == nullKind && (arg.isAntiquotSuffixSplice || arg.isAntiquotSplice) then
91
+ throwErrorAt arg "invalid auto tactic, antiquotation is not allowed"
92
+ else
93
+ let quotedArg ← quoteAutoTactic arg
94
+ quotedArgs := mkApp3 (.const ``Array.push [.zero]) ty quotedArgs quotedArg
95
+ return mkApp3 (.const ``Syntax.node []) (.const ``SourceInfo.none []) (toExpr k) quotedArgs
96
+ | .atom _ val => return .app (.const ``mkAtom []) (toExpr val)
97
+ | .missing => throwError "invalid auto tactic, tactic is missing"
98
+
99
+ /--
100
+ Adds a declaration whose value is a Syntax expression representing `tactic`.
101
+ If `name?` is provided, it is used for the declaration name, and otherwise a fresh name is generated.
102
+ Returns the declaration name.
103
+ -/
104
+ def declareTacticSyntax (tactic : Syntax) (name? : Option Name := none) : TermElabM Name :=
105
+ withFreshMacroScope do
106
+ let name ← name?.getDM do MonadQuotation.addMacroScope ((← getEnv).asyncPrefix?.getD .anonymous ++ `_auto)
107
+ let type := Lean.mkConst `Lean.Syntax
108
+ let value ← quoteAutoTactic tactic
109
+ trace[Elab.autoParam] value
110
+ let decl := Declaration.defnDecl { name, levelParams := [], type, value, hints := .opaque,
111
+ safety := DefinitionSafety.safe }
112
+ addDecl decl
113
+ modifyEnv (addMeta Β· name)
114
+ compileDecl decl
115
+ return name
116
+
117
+ /--
118
+ Expand `optional (binderTactic <|> binderDefault)`
119
+ ```
120
+ def binderTactic := leading_parser " := " >> " by " >> tacticParser
121
+ def binderDefault := leading_parser " := " >> termParser
122
+ ```
123
+ -/
124
+ private def expandBinderModifier (type : Syntax) (optBinderModifier : Syntax) : TermElabM Syntax := do
125
+ if optBinderModifier.isNone then
126
+ return type
127
+ else
128
+ let modifier := optBinderModifier[0]
129
+ let kind := modifier.getKind
130
+ if kind == `Lean.Parser.Term.binderDefault then
131
+ let defaultVal := modifier[1]
132
+ `(optParam $type $defaultVal)
133
+ else if kind == `Lean.Parser.Term.binderTactic then
134
+ let tac := modifier[2]
135
+ let name ← declareTacticSyntax tac
136
+ `(autoParam $type $(mkIdentFrom tac name))
137
+ else
138
+ throwUnsupportedSyntax
139
+
140
+ private def getBinderIds (ids : Syntax) : TermElabM (Array Syntax) :=
141
+ ids.getArgs.mapM fun id =>
142
+ let k := id.getKind
143
+ if k == identKind || k == `Lean.Parser.Term.hole then
144
+ return id
145
+ else
146
+ throwErrorAt id "identifier or `_` expected"
147
+
148
+ /--
149
+ Convert `stx` into an array of `BinderView`s.
150
+ `stx` must be an identifier, `_`, `explicitBinder`, `implicitBinder`, `strictImplicitBinder`, or `instBinder`.
151
+ -/
152
+ private def toBinderViews (stx : Syntax) : TermElabM (Array BinderView) := do
153
+ let k := stx.getKind
154
+ if stx.isIdent || k == ``hole then
155
+ -- binderIdent
156
+ return #[{ ref := stx, id := (← expandBinderIdent stx), type := mkHole stx, bi := .default }]
157
+ else if k == ``Lean.Parser.Term.explicitBinder then
158
+ -- `(` binderIdent+ binderType (binderDefault <|> binderTactic)? `)`
159
+ let ids ← getBinderIds stx[1]
160
+ let type := stx[2]
161
+ let optModifier := stx[3]
162
+ ids.mapM fun id => do pure { ref := id, id := (← expandBinderIdent id), type := (← expandBinderModifier (expandBinderType id type) optModifier), bi := .default }
163
+ else if k == ``Lean.Parser.Term.implicitBinder then
164
+ -- `{` binderIdent+ binderType `}`
165
+ let ids ← getBinderIds stx[1]
166
+ let type := stx[2]
167
+ ids.mapM fun id => do pure { ref := id, id := (← expandBinderIdent id), type := expandBinderType id type, bi := .implicit }
168
+ else if k == ``Lean.Parser.Term.strictImplicitBinder then
169
+ -- `⦃` binderIdent+ binderType `⦄`
170
+ let ids ← getBinderIds stx[1]
171
+ let type := stx[2]
172
+ ids.mapM fun id => do pure { ref := id, id := (← expandBinderIdent id), type := expandBinderType id type, bi := .strictImplicit }
173
+ else if k == ``Lean.Parser.Term.instBinder then
174
+ -- `[` optIdent type `]`
175
+ let id ← expandOptIdent stx[1]
176
+ let type := stx[2]
177
+ return #[ { ref := id, id := id, type := type, bi := .instImplicit } ]
178
+ else
179
+ throwUnsupportedSyntax
180
+
181
+ private def registerFailedToInferBinderTypeInfo (type : Expr) (ref : Syntax) : TermElabM Unit := do
182
+ registerCustomErrorIfMVar type ref "failed to infer binder type"
183
+ registerLevelMVarErrorExprInfo type ref m!"failed to infer universe levels in binder type"
184
+
185
+ def addLocalVarInfo (stx : Syntax) (fvar : Expr) : TermElabM Unit :=
186
+ addTermInfo' (isBinder := true) stx fvar
187
+
188
+ private def ensureAtomicBinderName (binderView : BinderView) : TermElabM Unit :=
189
+ let n := binderView.id.getId.eraseMacroScopes
190
+ unless n.isAtomic do
191
+ throwErrorAt binderView.id "invalid binder name '{n}', it must be atomic"
192
+
193
+ register_builtin_option checkBinderAnnotations : Bool := {
194
+ defValue := true
195
+ descr := "check whether type is a class instance whenever the binder annotation `[...]` is used"
196
+ }
197
+
198
+ /-- Throw an error if `type` is not a valid local instance. -/
199
+ private partial def checkLocalInstanceParameters (type : Expr) : TermElabM Unit := do
200
+ let .forallE n d b bi ← whnf type | return ()
201
+ -- We allow instance arguments so that local instances of the form
202
+ -- `variable [βˆ€ (a : Ξ±) [P a], Q a]`
203
+ -- are accepted, per https://github.com/leanprover/lean4/issues/2311
204
+ if bi != .instImplicit && !b.hasLooseBVar 0 then
205
+ throwError "invalid parametric local instance, parameter with type{indentExpr d}\ndoes not have forward dependencies, type class resolution cannot use this kind of local instance because it will not be able to infer a value for this parameter."
206
+ withLocalDecl n bi d fun x => checkLocalInstanceParameters (b.instantiate1 x)
207
+
208
+ private partial def elabBinderViews (binderViews : Array BinderView) (fvars : Array (Syntax Γ— Expr)) (k : Array (Syntax Γ— Expr) β†’ TermElabM Ξ±)
209
+ : TermElabM Ξ± :=
210
+ let rec loop (i : Nat) (fvars : Array (Syntax Γ— Expr)) : TermElabM Ξ± := do
211
+ if h : i < binderViews.size then
212
+ let binderView := binderViews[i]
213
+ ensureAtomicBinderName binderView
214
+ let type ← elabType binderView.type
215
+ registerFailedToInferBinderTypeInfo type binderView.type
216
+ if binderView.bi.isInstImplicit && checkBinderAnnotations.get (← getOptions) then
217
+ unless (← isClass? type).isSome do
218
+ throwErrorAt binderView.type (m!"invalid binder annotation, type is not a class instance{indentExpr type}" ++ .note "Use the command `set_option checkBinderAnnotations false` to disable the check")
219
+ withRef binderView.type <| checkLocalInstanceParameters type
220
+ let id := binderView.id.getId
221
+ let kind := kindOfBinderName id
222
+ withLocalDecl id binderView.bi type (kind := kind) fun fvar => do
223
+ addLocalVarInfo binderView.ref fvar
224
+ loop (i+1) (fvars.push (binderView.id, fvar))
225
+ else
226
+ k fvars
227
+ loop 0 fvars
228
+
229
+ private partial def elabBindersAux (binders : Array Syntax) (k : Array (Syntax Γ— Expr) β†’ TermElabM Ξ±) : TermElabM Ξ± :=
230
+ let rec loop (i : Nat) (fvars : Array (Syntax Γ— Expr)) : TermElabM Ξ± := do
231
+ if h : i < binders.size then
232
+ let binderViews ← toBinderViews binders[i]
233
+ elabBinderViews binderViews fvars <| loop (i+1)
234
+ else
235
+ k fvars
236
+ loop 0 #[]
237
+
238
+ /--
239
+ Like `elabBinders`, but also pass syntax node per binder.
240
+ `elabBinders(Ex)` automatically adds binder info nodes for the produced fvars, but storing the syntax nodes
241
+ might be necessary when later adding the same binders back to the local context so that info nodes can
242
+ manually be added for the new fvars; see `MutualDef` for an example. -/
243
+ def elabBindersEx (binders : Array Syntax) (k : Array (Syntax Γ— Expr) β†’ TermElabM Ξ±) : TermElabM Ξ± :=
244
+ universeConstraintsCheckpoint do
245
+ if binders.isEmpty then
246
+ k #[]
247
+ else
248
+ elabBindersAux binders k
249
+
250
+ /--
251
+ Elaborate the given binders (i.e., `Syntax` objects for `bracketedBinder`),
252
+ update the local context, set of local instances, reset instance cache (if needed), and then
253
+ execute `k` with the updated context.
254
+ The local context will only be included inside `k`.
255
+
256
+ For example, suppose you have binders `[(a : Ξ±), (b : Ξ² a)]`, then the elaborator will
257
+ create two new free variables `a` and `b`, push these to the context and pass to `k #[a,b]`.
258
+ -/
259
+ def elabBinders (binders : Array Syntax) (k : Array Expr β†’ TermElabM Ξ±) : TermElabM Ξ± :=
260
+ elabBindersEx binders (fun fvars => k (fvars.map (Β·.2)))
261
+
262
+ /-- Same as `elabBinder` with a single binder.-/
263
+ def elabBinder (binder : Syntax) (x : Expr β†’ TermElabM Ξ±) : TermElabM Ξ± :=
264
+ elabBinders #[binder] fun fvars => x fvars[0]!
265
+
266
+ /-- If `binder` is a `_` or an identifier, return a `bracketedBinder` using `type` otherwise throw an exception. -/
267
+ def expandSimpleBinderWithType (type : Term) (binder : Syntax) : MacroM Syntax :=
268
+ if binder.isOfKind ``hole || binder.isIdent then
269
+ `(bracketedBinderF| ($binder : $type))
270
+ else
271
+ Macro.throwErrorAt type "unexpected type ascription"
272
+
273
+ @[builtin_macro Lean.Parser.Term.forall] def expandForall : Macro
274
+ | `(forall $binders* : $ty, $term) => do
275
+ let binders ← binders.mapM (expandSimpleBinderWithType ty)
276
+ `(forall $binders*, $term)
277
+ | _ => Macro.throwUnsupported
278
+
279
+ @[builtin_term_elab Β«forallΒ»] def elabForall : TermElab := fun stx _ =>
280
+ match stx with
281
+ | `(forall $binders*, $term) =>
282
+ elabBinders binders fun xs => do
283
+ let e ← elabType term
284
+ mkForallFVars xs e
285
+ | _ => throwUnsupportedSyntax
286
+
287
+ open Lean.Elab.Term.Quotation in
288
+ @[builtin_quot_precheck Lean.Parser.Term.arrow] def precheckArrow : Precheck
289
+ | `($dom:term -> $rng) => do
290
+ precheck dom
291
+ precheck rng
292
+ | _ => throwUnsupportedSyntax
293
+
294
+ @[builtin_term_elab arrow] def elabArrow : TermElab := fun stx _ =>
295
+ match stx with
296
+ | `($dom:term -> $rng) => do
297
+ -- elaborate independently from each other
298
+ let dom ← elabType dom
299
+ let rng ← elabType rng
300
+ return mkForall (← MonadQuotation.addMacroScope `a) BinderInfo.default dom rng
301
+ | _ => throwUnsupportedSyntax
302
+
303
+ /--
304
+ The dependent arrow. `(x : Ξ±) β†’ Ξ²` is equivalent to `βˆ€ x : Ξ±, Ξ²`, but we usually
305
+ reserve the latter for propositions. Also written as `Ξ  x : Ξ±, Ξ²` (the "Pi-type")
306
+ in the literature. -/
307
+ @[builtin_term_elab depArrow] def elabDepArrow : TermElab := fun stx _ =>
308
+ -- bracketedBinder `->` term
309
+ let binder := stx[0]
310
+ let term := stx[2]
311
+ elabBinders #[binder] fun xs => do
312
+ mkForallFVars xs (← elabType term)
313
+
314
+ /--
315
+ Auxiliary functions for converting `id_1 ... id_n` application into `#[id_1, ..., id_m]`
316
+ It is used at `expandFunBinders`. -/
317
+ private partial def getFunBinderIds? (stx : Syntax) : OptionT MacroM (Array Syntax) :=
318
+ let convertElem (stx : Term) : OptionT MacroM Syntax :=
319
+ match stx with
320
+ | `(_) =>
321
+ /-
322
+ We used to use `mkFreshIdent` here,
323
+ but it prevented us from obtaining hover info for `_` because the
324
+ fresh identifier would have a synthetic position, and synthetic positions
325
+ are ignored by the LSP server.
326
+ See comment at `BinderView.ref` for additional details.
327
+ -/
328
+ return stx
329
+ | `($_:ident) => return stx
330
+ | _ => failure
331
+ match stx with
332
+ | `($f $args*) => do
333
+ let mut acc := #[].push (← convertElem f)
334
+ for arg in args do
335
+ acc := acc.push (← convertElem arg)
336
+ return acc
337
+ | _ =>
338
+ return #[].push (← convertElem stx)
339
+
340
+ /--
341
+ Auxiliary function for expanding `fun` notation binders. Recall that `fun` parser is defined as
342
+ ```
343
+ def funBinder : Parser := implicitBinder <|> instBinder <|> termParser maxPrec
344
+ leading_parser unicodeSymbol "Ξ»" "fun" >> many1 funBinder >> "=>" >> termParser
345
+ ```
346
+ to allow notation such as `fun (a, b) => a + b`, where `(a, b)` should be treated as a pattern.
347
+ The result is a pair `(explicitBinders, newBody)`, where `explicitBinders` is syntax of the form
348
+ ```
349
+ `(` ident `:` term `)`
350
+ ```
351
+ which can be elaborated using `elabBinders`, and `newBody` is the updated `body` syntax.
352
+ We update the `body` syntax when expanding the pattern notation.
353
+ Example: `fun (a, b) => a + b` expands into `fun _a_1 => match _a_1 with | (a, b) => a + b`.
354
+ See local function `processAsPattern` at `expandFunBindersAux`.
355
+
356
+ The resulting `Bool` is true if a pattern was found. We use it "mark" a macro expansion. -/
357
+ partial def expandFunBinders (binders : Array Syntax) (body : Syntax) : MacroM (Array Syntax Γ— Syntax Γ— Bool) :=
358
+ let rec loop (body : Syntax) (i : Nat) (newBinders : Array Syntax) := do
359
+ if h : i < binders.size then
360
+ let binder := binders[i]
361
+ let processAsPattern : Unit β†’ MacroM (Array Syntax Γ— Syntax Γ— Bool) := fun _ => do
362
+ let pattern := binder
363
+ let major ← mkFreshIdent binder
364
+ let (binders, newBody, _) ← loop body (i+1) (newBinders.push $ mkExplicitBinder major (mkHole binder))
365
+ let newBody ← `(match $major:ident with | $pattern => $newBody)
366
+ pure (binders, newBody, true)
367
+ match binder.getKind with
368
+ | ``Lean.Parser.Term.implicitBinder
369
+ | ``Lean.Parser.Term.strictImplicitBinder
370
+ | ``Lean.Parser.Term.instBinder
371
+ | ``Lean.Parser.Term.explicitBinder
372
+ | ``Lean.Parser.Term.hole | `ident => loop body (i+1) (newBinders.push binder)
373
+ | ``Lean.Parser.Term.paren =>
374
+ let term := binder[1]
375
+ match (← getFunBinderIds? term) with
376
+ | some idents =>
377
+ -- `fun (x ...) ...` ~> `fun (x : _) ...`
378
+ -- Interpret `(x ...)` as sequence of binders instead of pattern only if none of the idents
379
+ -- are defined in the global scope. Technically, it would be sufficient to only check the
380
+ -- first ident to be sure that the syntax cannot possibly be a valid pattern. However, for
381
+ -- consistency we apply the same check to all idents so that the possibility of shadowing
382
+ -- a global decl is identical for all of them.
383
+ if (← idents.allM fun ident => return List.isEmpty (← Macro.resolveGlobalName ident.getId)) then
384
+ loop body (i+1) (newBinders ++ idents.map (mkExplicitBinder Β· (mkHole binder)))
385
+ else
386
+ processAsPattern ()
387
+ | none => processAsPattern ()
388
+ | ``Lean.Parser.Term.typeAscription =>
389
+ let term := binder[1]
390
+ let type := binder[3].getOptional?.getD (mkHole binder)
391
+ match (← getFunBinderIds? term) with
392
+ | some idents => loop body (i+1) (newBinders ++ idents.map (fun ident => mkExplicitBinder ident type))
393
+ | none => processAsPattern ()
394
+ | _ => processAsPattern ()
395
+ else
396
+ pure (newBinders, body, false)
397
+ loop body 0 #[]
398
+
399
+ namespace FunBinders
400
+
401
+ structure State where
402
+ fvars : Array Expr := #[]
403
+ lctx : LocalContext
404
+ localInsts : LocalInstances
405
+ expectedType? : Option Expr := none
406
+
407
+ private def propagateExpectedType (fvar : Expr) (fvarType : Expr) (s : State) : TermElabM State := do
408
+ match s.expectedType? with
409
+ | none => pure s
410
+ | some expectedType =>
411
+ let expectedType ← whnfForall expectedType
412
+ match expectedType with
413
+ | .forallE _ d b _ =>
414
+ discard <| isDefEq fvarType d
415
+ let b := b.instantiate1 fvar
416
+ return { s with expectedType? := some b }
417
+ | _ =>
418
+ return { s with expectedType? := none }
419
+
420
+ private partial def elabFunBinderViews (binderViews : Array BinderView) (i : Nat) (s : State) : TermElabM State := do
421
+ if h : i < binderViews.size then
422
+ let binderView := binderViews[i]
423
+ ensureAtomicBinderName binderView
424
+ withRef binderView.type <| withLCtx s.lctx s.localInsts do
425
+ let type ← elabType binderView.type
426
+ registerFailedToInferBinderTypeInfo type binderView.type
427
+ let fvarId ← mkFreshFVarId
428
+ let fvar := mkFVar fvarId
429
+ let s := { s with fvars := s.fvars.push fvar }
430
+ let id := binderView.id.getId
431
+ let kind := kindOfBinderName id
432
+ /-
433
+ We do **not** want to support default and auto arguments in lambda abstractions.
434
+ Example: `fun (x : Nat := 10) => x+1`.
435
+ We do not believe this is an useful feature, and it would complicate the logic here.
436
+ -/
437
+ let lctx := s.lctx.mkLocalDecl fvarId id type binderView.bi kind
438
+ addTermInfo' (lctx? := some lctx) (isBinder := true) binderView.ref fvar
439
+ let s ← withRef binderView.id <| propagateExpectedType fvar type s
440
+ let s := { s with lctx }
441
+ match ← isClass? type, kind with
442
+ | some className, .default =>
443
+ let localInsts := s.localInsts.push { className, fvar := mkFVar fvarId }
444
+ elabFunBinderViews binderViews (i+1) { s with localInsts }
445
+ | _, _ => elabFunBinderViews binderViews (i+1) s
446
+ else
447
+ pure s
448
+
449
+ partial def elabFunBindersAux (binders : Array Syntax) (i : Nat) (s : State) : TermElabM State := do
450
+ if h : i < binders.size then
451
+ let binderViews ← toBinderViews binders[i]
452
+ let s ← elabFunBinderViews binderViews 0 s
453
+ elabFunBindersAux binders (i+1) s
454
+ else
455
+ pure s
456
+
457
+ end FunBinders
458
+
459
+ def elabFunBinders (binders : Array Syntax) (expectedType? : Option Expr) (x : Array Expr β†’ Option Expr β†’ TermElabM οΏ½οΏ½) : TermElabM Ξ± :=
460
+ if binders.isEmpty then
461
+ x #[] expectedType?
462
+ else do
463
+ let lctx ← getLCtx
464
+ let localInsts ← getLocalInstances
465
+ let s ← FunBinders.elabFunBindersAux binders 0 { lctx, localInsts, expectedType? }
466
+ withLCtx s.lctx s.localInsts do
467
+ x s.fvars s.expectedType?
468
+
469
+ def expandWhereDecls (whereDecls : Syntax) (body : Syntax) : MacroM Syntax :=
470
+ match whereDecls with
471
+ | `(whereDecls|where $[$_:whereFinally]?) => `($body)
472
+ | `(whereDecls|where $[$decls:letRecDecl];* $[$_:whereFinally]?) => `(let rec $decls:letRecDecl,*; $body)
473
+ | _ => Macro.throwUnsupported
474
+
475
+ def expandWhereDeclsOpt (whereDeclsOpt : Syntax) (body : Syntax) : MacroM Syntax :=
476
+ if whereDeclsOpt.isNone then
477
+ return body
478
+ else
479
+ expandWhereDecls whereDeclsOpt[0] body
480
+
481
+ /--
482
+ Helper function for `expandMatchAltsIntoMatch`.
483
+ -/
484
+ private def expandMatchAltsIntoMatchAux (matchAlts : Syntax) (isTactic : Bool) (useExplicit : Bool) : Nat β†’ Array Syntax β†’ Array Ident β†’ MacroM Syntax
485
+ | 0, discrs, xs => do
486
+ if isTactic then
487
+ `(tactic|match $[$discrs:term],* with $matchAlts:matchAlts)
488
+ else
489
+ let stx ← `(match $[$discrs:term],* with $matchAlts:matchAlts)
490
+ clearInMatch stx xs
491
+ | n+1, discrs, xs => withFreshMacroScope do
492
+ let x ← `(x) -- If this were implementation-detail, the `contradiction` tactic used by match would not find it.
493
+ let d ← `(@$x:ident)
494
+ let body ← expandMatchAltsIntoMatchAux matchAlts isTactic useExplicit n (discrs.push d) (xs.push x)
495
+ if isTactic then
496
+ `(tactic| intro $x:term; $body:tactic)
497
+ else if useExplicit then
498
+ `(@fun $x => $body)
499
+ else
500
+ `(fun $x => $body)
501
+
502
+ /--
503
+ Expand `matchAlts` syntax into a full `match`-expression.
504
+ Example:
505
+ ```
506
+ | 0, true => alt_1
507
+ | i, _ => alt_2
508
+ ```
509
+ expands into (for tactic == false)
510
+ ```
511
+ fun x_1 x_2 =>
512
+ match @x_1, @x_2 with
513
+ | 0, true => alt_1
514
+ | i, _ => alt_2
515
+ ```
516
+ and (for tactic == true)
517
+ ```
518
+ intro x_1; intro x_2;
519
+ match @x_1, @x_2 with
520
+ | 0, true => alt_1
521
+ | i, _ => alt_2
522
+ ```
523
+
524
+ If `useExplicit = true`, we add a `@` before `fun` to disable implicit lambdas. We disable them when processing `let` and `let rec` declarations
525
+ to make sure the behavior is consistent with top-level declarations where we can write
526
+ ```
527
+ def f : {Ξ± : Type} β†’ Ξ± β†’ Ξ±
528
+ | _, a => a
529
+ ```
530
+ We use `useExplicit = false` when we are elaborating the `fun | ... => ... | ...` notation. See issue #1132.
531
+ If `@fun` is used with this notation, the we set `useExplicit = true`.
532
+ We also use `useExplicit = false` when processing `instance ... where` notation declarations. The motivation is to have compact declarations such as
533
+ ```
534
+ instance [Alternative m] : MonadLiftT Option m where
535
+ monadLift -- We don't want to provide the implicit arguments of `monadLift` here. One should use `monadLift := @fun ...` if they want to provide them.
536
+ | some a => pure a
537
+ | none => failure
538
+ ```
539
+
540
+ Remark: we add `@` at discriminants to make sure we don't consume implicit arguments, and to make the behavior consistent with `fun`.
541
+ Example:
542
+ ```
543
+ inductive T : Type 1 :=
544
+ | mkT : (forall {a : Type}, a -> a) -> T
545
+
546
+ def makeT (f : forall {a : Type}, a -> a) : T :=
547
+ mkT f
548
+
549
+ def makeT' : (forall {a : Type}, a -> a) -> T
550
+ | f => mkT f
551
+ ```
552
+ The two definitions should be elaborated without errors and be equivalent.
553
+ -/
554
+ def expandMatchAltsIntoMatch (ref : Syntax) (matchAlts : Syntax) (useExplicit := true) : MacroM Syntax :=
555
+ withRef ref <| expandMatchAltsIntoMatchAux matchAlts (isTactic := false) (useExplicit := useExplicit) (getMatchAltsNumPatterns matchAlts) #[] #[]
556
+
557
+ def expandMatchAltsIntoMatchTactic (ref : Syntax) (matchAlts : Syntax) : MacroM Syntax :=
558
+ withRef ref <| expandMatchAltsIntoMatchAux matchAlts (isTactic := true) (useExplicit := false) (getMatchAltsNumPatterns matchAlts) #[] #[]
559
+
560
+ /--
561
+ Sanity-checks the number of patterns in each alternative of a definition by pattern matching.
562
+ Specifically, verifies that all alternatives have the same number of patterns and that the number
563
+ of patterns is upper-bounded by the number of (dependent) arrows in the expected type.
564
+
565
+ Note: This function assumes that the number of patterns in the first alternative will be equal to
566
+ `numDiscrs` (since we use the first alternative to infer the arity of the generated matcher in
567
+ `getMatchAltsNumPatterns`).
568
+ -/
569
+ private def checkMatchAltPatternCounts (matchAlts : Syntax) (numDiscrs : Nat) (expectedType : Expr)
570
+ : MetaM Unit := do
571
+ let sepPats (pats : List Syntax) := MessageData.joinSep (pats.map toMessageData) ", "
572
+ let maxDiscrs? ← forallTelescopeReducing expectedType fun xs e =>
573
+ if e.getAppFn.isMVar then pure none else pure (some xs.size)
574
+ let matchAltViews := matchAlts[0].getArgs.filterMap getMatchAlt
575
+ let numPatternsStr (n : Nat) := s!"{n} {if n == 1 then "pattern" else "patterns"}"
576
+ if h : matchAltViews.size > 0 then
577
+ if let some maxDiscrs := maxDiscrs? then
578
+ if numDiscrs > maxDiscrs then
579
+ if maxDiscrs == 0 then
580
+ throwErrorAt matchAltViews[0].lhs m!"Cannot define a value of type{indentExpr expectedType}\n\
581
+ by pattern matching because it is not a function type"
582
+ else
583
+ throwErrorAt matchAltViews[0].lhs m!"Too many patterns in match alternative: \
584
+ At most {numPatternsStr maxDiscrs} expected in a definition of type {indentExpr expectedType}\n\
585
+ but found {numDiscrs}:{indentD <| sepPats matchAltViews[0].patterns.toList}"
586
+ -- Catch inconsistencies between pattern counts here so that we can report them as "inconsistent"
587
+ -- rather than as "too many" or "too few" (as the `match` elaborator does)
588
+ for view in matchAltViews do
589
+ let numPats := view.patterns.size
590
+ if numPats != numDiscrs then
591
+ let origPats := sepPats matchAltViews[0].patterns.toList
592
+ let pats := sepPats view.patterns.toList
593
+ throwErrorAt view.lhs m!"Inconsistent number of patterns in match alternatives: This \
594
+ alternative contains {numPatternsStr numPats}:{indentD pats}\n\
595
+ but a preceding alternative contains {numDiscrs}:{indentD origPats}"
596
+
597
+ /--
598
+ Similar to `expandMatchAltsIntoMatch`, but supports an optional `where` clause.
599
+
600
+ Expand `matchAltsWhereDecls` into `let rec` + `match`-expression.
601
+ Example
602
+ ```
603
+ | 0, true => ... f 0 ...
604
+ | i, _ => ... f i + g i ...
605
+ where
606
+ f x := g x + 1
607
+
608
+ g : Nat β†’ Nat
609
+ | 0 => 1
610
+ | x+1 => f x
611
+ ```
612
+ expands into
613
+ ```
614
+ fux x_1 x_2 =>
615
+ let rec
616
+ f x := g x + 1,
617
+ g : Nat β†’ Nat
618
+ | 0 => 1
619
+ | x+1 => f x
620
+ match x_1, x_2 with
621
+ | 0, true => ... f 0 ...
622
+ | i, _ => ... f i + g i ...
623
+ ```
624
+ -/
625
+ def expandMatchAltsWhereDecls (matchAltsWhereDecls : Syntax) (expectedType : Expr) : TermElabM Syntax :=
626
+ let matchAlts := matchAltsWhereDecls[0]
627
+ -- matchAltsWhereDecls[1] is the termination hints, collected elsewhere
628
+ let whereDeclsOpt := matchAltsWhereDecls[2]
629
+ let rec loop (i : Nat) (discrs : Array Syntax) : TermElabM Syntax :=
630
+ match i with
631
+ | 0 => do
632
+ checkMatchAltPatternCounts matchAlts discrs.size expectedType
633
+ let matchStx ← `(match $[@$discrs:term],* with $matchAlts:matchAlts)
634
+ liftMacroM do
635
+ let matchStx ← clearInMatch matchStx discrs
636
+ if whereDeclsOpt.isNone then
637
+ return matchStx
638
+ else
639
+ expandWhereDeclsOpt whereDeclsOpt matchStx
640
+ | n+1 => withFreshMacroScope do
641
+ let body ← loop n (discrs.push (← `(x)))
642
+ `(@fun x => $body)
643
+ loop (getMatchAltsNumPatterns matchAlts) #[]
644
+
645
+ @[builtin_macro Parser.Term.fun] partial def expandFun : Macro
646
+ | `(fun $binders* : $ty => $body) => do
647
+ let binders ← binders.mapM (expandSimpleBinderWithType ty)
648
+ `(fun $binders* => $body)
649
+ | `(fun $binders* => $body) => do -- if there is a type ascription, we assume all binders are already simple
650
+ let (binders, body, expandedPattern) ← expandFunBinders binders body
651
+ if expandedPattern then
652
+ `(fun $binders* => $body)
653
+ else
654
+ Macro.throwUnsupported
655
+ | stx@`(fun $m:matchAlts) => expandMatchAltsIntoMatch stx m (useExplicit := false)
656
+ | _ => Macro.throwUnsupported
657
+
658
+ @[builtin_macro Parser.Term.explicit] partial def expandExplicitFun : Macro := fun stx =>
659
+ match stx with
660
+ | `(@fun $m:matchAlts) => expandMatchAltsIntoMatch stx[1] m (useExplicit := true)
661
+ | _ => Macro.throwUnsupported
662
+
663
+ open Lean.Elab.Term.Quotation in
664
+ @[builtin_quot_precheck Lean.Parser.Term.fun] def precheckFun : Precheck
665
+ | `(fun $binders* $[: $ty?]? => $body) => do
666
+ let (binders, body, _) ← liftMacroM <| expandFunBinders binders body
667
+ let mut ids := #[]
668
+ for b in binders do
669
+ for v in ← toBinderViews b do
670
+ Quotation.withNewLocals ids <| precheck v.type
671
+ ids := ids.push v.id.getId
672
+ Quotation.withNewLocals ids <| precheck body
673
+ | _ => throwUnsupportedSyntax
674
+
675
+ @[builtin_term_elab Β«funΒ»] partial def elabFun : TermElab := fun stx expectedType? =>
676
+ match stx with
677
+ | `(fun $binders* => $body) => do
678
+ -- We can assume all `match` binders have been iteratively expanded by the above macro here, though
679
+ -- we still need to call `expandFunBinders` once to obtain `binders` in a normal form
680
+ -- expected by `elabFunBinder`.
681
+ let (binders, body, _) ← liftMacroM <| expandFunBinders binders body
682
+ elabFunBinders binders expectedType? fun xs expectedType? => do
683
+ /- We ensure the expectedType here since it will force coercions to be applied if needed.
684
+ If we just use `elabTerm`, then we will need to a coercion `Coe (Ξ± β†’ Ξ²) (Ξ± β†’ Ξ΄)` whenever there is a coercion `Coe Ξ² Ξ΄`,
685
+ and another instance for the dependent version. -/
686
+ let e ← elabTermEnsuringType body expectedType?
687
+ mkLambdaFVars xs e
688
+ | _ => throwUnsupportedSyntax
689
+
690
+ /--
691
+ Configuration for `let` elaboration.
692
+ -/
693
+ structure LetConfig where
694
+ /-- Elaborate as a nondependent `let` (a `have`). -/
695
+ nondep : Bool := false
696
+ /-- Eliminate the `let` if it is unused by the body. -/
697
+ usedOnly : Bool := false
698
+ /-- Zeta reduces (inlines) the `let`. -/
699
+ zeta : Bool := false
700
+ /-- Postpone elaboration of the value until after the body is elaborated. -/
701
+ postponeValue : Bool := false
702
+ /-- Generalize the value from the expected type when elaborating the body. -/
703
+ generalize : Bool := false
704
+ /-- For `let x := v; b`, adds `eq : x = v` to the context. -/
705
+ eq? : Option Ident := none
706
+
707
+ def LetConfig.setFrom (config : LetConfig) (key : Syntax) (val : Bool) : LetConfig :=
708
+ if key.isOfKind ``Parser.Term.letOptNondep then
709
+ { config with nondep := val }
710
+ else if key.isOfKind ``Parser.Term.letOptUsedOnly then
711
+ { config with usedOnly := val }
712
+ else if key.isOfKind ``Parser.Term.letOptZeta then
713
+ { config with zeta := val }
714
+ else if key.isOfKind ``Parser.Term.letOptPostponeValue then
715
+ { config with postponeValue := val }
716
+ else if key.isOfKind ``Parser.Term.letOptGeneralize then
717
+ { config with generalize := val }
718
+ else
719
+ config
720
+
721
+ /--
722
+ Interprets a `Parser.Term.letConfig`.
723
+ -/
724
+ def mkLetConfig (letConfig : Syntax) (initConfig : LetConfig) : TermElabM LetConfig := do
725
+ let mut config := initConfig
726
+ unless letConfig.isOfKind ``Parser.Term.letConfig do
727
+ return config
728
+ for item in letConfig[0].getArgs do
729
+ match item with
730
+ | `(letPosOpt| +$opt:letOpts) => config := config.setFrom opt.raw[0] true
731
+ | `(letNegOpt| -$opt:letOpts) => config := config.setFrom opt.raw[0] false
732
+ | `(letOptEq| (eq := $n:ident)) => config := { config with eq? := n }
733
+ | `(letOptEq| (eq := $b)) => config := { config with eq? := mkIdentFrom b (canonical := true) (← mkFreshBinderNameForTactic `h) }
734
+ | _ => pure ()
735
+ return config
736
+
737
+ /--
738
+ The default elaboration order is `binders`, `typeStx`, `valStx`, and `body`.
739
+ If `config.postponeValue == true`, then we use the order `binders`, `typeStx`, `body`, and `valStx`.
740
+ If `config.generalize == true`, then the value is abstracted from the expected type when elaborating the body.
741
+ -/
742
+ def elabLetDeclAux (id : Syntax) (binders : Array Syntax) (typeStx : Syntax) (valStx : Syntax) (body : Syntax)
743
+ (expectedType? : Option Expr) (config : LetConfig) : TermElabM Expr := do
744
+ if config.generalize then
745
+ if config.postponeValue then
746
+ throwError "`+postponeValue` and `+generalize` are incompatible"
747
+ tryPostponeIfNoneOrMVar expectedType?
748
+ let (type, val, binders) ← elabBindersEx binders fun xs => do
749
+ let (binders, fvars) := xs.unzip
750
+ /-
751
+ We use `withSynthesize` to ensure that any postponed elaboration problem
752
+ and nested tactics in `type` are resolved before elaborating `val`.
753
+ Resolved: we want to avoid synthetic opaque metavariables in `type`.
754
+ Recall that this kind of metavariable is non-assignable, and `isDefEq`
755
+ may waste a lot of time unfolding declarations before failing.
756
+ See issue #4051 for an example.
757
+
758
+ Here is the analysis for issue #4051.
759
+ - Given `have x : type := value; body`, we were previously elaborating `value` even
760
+ if `type` contained postponed elaboration problems.
761
+ - Moreover, the metavariables in `type` corresponding to postponed elaboration
762
+ problems cannot be assigned by `isDefEq` since the elaborator is supposed to assign them.
763
+ - Then, when checking whether type of `value` is definitionally equal to `type`,
764
+ a very long-time was spent unfolding a bunch of declarations before it failed.
765
+ In #4051, it was unfolding `Array.swaps` which is defined by well-founded recursion.
766
+ After the failure, the elaborator inserted a postponed coercion
767
+ that would be resolved later as soon as the types don't have unassigned metavariables.
768
+
769
+ We use `postpone := .partial` to allow type class (TC) resolution problems to be postponed
770
+ Recall that TC resolution does **not** produce synthetic opaque metavariables.
771
+ -/
772
+ let type ← withSynthesize (postpone := .partial) <| elabType typeStx
773
+ let letMsg := if config.nondep then "have" else "let"
774
+ registerCustomErrorIfMVar type typeStx m!"failed to infer '{letMsg}' declaration type"
775
+ registerLevelMVarErrorExprInfo type typeStx m!"failed to infer universe levels in '{letMsg}' declaration type"
776
+ if config.postponeValue then
777
+ let type ← mkForallFVars fvars type
778
+ let val ← mkFreshExprMVar type
779
+ pure (type, val, binders)
780
+ else
781
+ let val ← elabTermEnsuringType valStx type
782
+ let type ← mkForallFVars fvars type
783
+ /- By default `mkLambdaFVars` and `mkLetFVars` create binders only for let-declarations that are actually used
784
+ in the body. This generates counterintuitive behavior in the elaborator since users will not be notified
785
+ about holes such as
786
+ ```
787
+ def ex : Nat :=
788
+ let x := _
789
+ 42
790
+ ```
791
+ -/
792
+ let val ← mkLambdaFVars fvars val (usedLetOnly := false)
793
+ pure (type, val, binders)
794
+ let kind := kindOfBinderName id.getId
795
+ trace[Elab.let.decl] "{id.getId} : {type} := {val}"
796
+ let result ←
797
+ withLetDecl id.getId (kind := kind) type val (nondep := config.nondep) fun x => do
798
+ let elabBody : TermElabM Expr := do
799
+ let mut expectedType? := expectedType?
800
+ if config.generalize then
801
+ let throwNoType := throwError "failed to elaborate with `+generalize`, expected type is not available"
802
+ let some expectedType := expectedType? | throwNoType
803
+ let expectedType ← instantiateMVars expectedType
804
+ if expectedType.getAppFn.isMVar then throwNoType
805
+ let motiveBody ← kabstract expectedType (← instantiateMVars val)
806
+ let motive := motiveBody.instantiate1 x
807
+ -- When `config.nondep` is false, then `motive` will be definitionally equal to `expectedType`.
808
+ -- Type correctness only needs to be checked in the `nondep` case:
809
+ if config.nondep then
810
+ unless (← isTypeCorrect motive) do
811
+ throwError "failed to elaborate with `+generalize`, generalized expected type is not type correct:{indentD motive}"
812
+ expectedType? := motive
813
+ elabTermEnsuringType body expectedType? >>= instantiateMVars
814
+ addLocalVarInfo id x
815
+ match config.eq? with
816
+ | none =>
817
+ let body ← elabBody
818
+ if config.zeta then
819
+ pure <| (← body.abstractM #[x]).instantiate1 val
820
+ else
821
+ mkLetFVars #[x] body (usedLetOnly := config.usedOnly) (generalizeNondepLet := false)
822
+ | some h =>
823
+ let hTy ← mkEq x val
824
+ withLetDecl h.getId hTy (← mkEqRefl x) (nondep := true) fun h' => do
825
+ addLocalVarInfo h h'
826
+ let body ← elabBody
827
+ if config.zeta then
828
+ pure <| (← body.abstractM #[x, h']).instantiateRev #[val, ← mkEqRefl val]
829
+ else if config.nondep then
830
+ -- TODO(kmill): Think more about how to encode this case.
831
+ -- Currently we produce `(fun (x : Ξ±) (h : x = val) => b) val rfl`.
832
+ -- N.B. the nondep lets become lambdas here.
833
+ let f ← mkLambdaFVars #[x, h'] body
834
+ return mkApp2 f val (← mkEqRefl val)
835
+ else
836
+ mkLetFVars #[x, h'] body (usedLetOnly := config.usedOnly) (generalizeNondepLet := false)
837
+ if config.postponeValue then
838
+ forallBoundedTelescope type binders.size fun xs type => do
839
+ -- the original `fvars` from above are gone, so add back info manually
840
+ for b in binders, x in xs do
841
+ addLocalVarInfo b x
842
+ let valResult ← elabTermEnsuringType valStx type
843
+ let valResult ← mkLambdaFVars xs valResult (usedLetOnly := false)
844
+ unless (← isDefEq val valResult) do
845
+ throwError "unexpected error when elaborating 'let'"
846
+ pure result
847
+
848
+ structure LetIdDeclView where
849
+ id : Syntax
850
+ binders : Array Syntax
851
+ type : Syntax
852
+ value : Syntax
853
+
854
+ def mkLetIdDeclView (letIdDecl : Syntax) : LetIdDeclView :=
855
+ /-
856
+ def letId := leading_parser binderIdent <|> hygieneInfo
857
+ def letIdBinder := binderIdent <|> bracketedBinder
858
+ def letIdLhs := letId >> many letIdBinder >> optType
859
+ def letIdDecl := leading_parser letIdLhs >> " := " >> termParser
860
+ -/
861
+ let letId := letIdDecl[0]
862
+ let id :=
863
+ if letId[0].isOfKind hygieneInfoKind then
864
+ HygieneInfo.mkIdent letId[0] `this (canonical := true)
865
+ else
866
+ -- Assumed to be binderIdent
867
+ letId[0]
868
+ let binders := letIdDecl[1].getArgs
869
+ let optType := letIdDecl[2]
870
+ let type := expandOptType id optType
871
+ let value := letIdDecl[4]
872
+ { id, binders, type, value }
873
+
874
+ def expandLetEqnsDecl (letDecl : Syntax) (useExplicit := true) : MacroM Syntax := do
875
+ let ref := letDecl
876
+ let matchAlts := letDecl[3]
877
+ let val ← expandMatchAltsIntoMatch ref matchAlts (useExplicit := useExplicit)
878
+ return mkNode `Lean.Parser.Term.letIdDecl #[letDecl[0], letDecl[1], letDecl[2], mkAtomFrom ref " := ", val]
879
+
880
+ def elabLetDeclCore (stx : Syntax) (expectedType? : Option Expr) (initConfig : LetConfig) : TermElabM Expr := do
881
+ let (config, declIdx) ← if stx[1].isOfKind ``Parser.Term.letConfig then
882
+ pure (← mkLetConfig stx[1] initConfig, 2)
883
+ else
884
+ pure (initConfig, 1)
885
+ let letDecl := stx[declIdx][0]
886
+ let body := stx[declIdx + 2]
887
+ if letDecl.getKind == ``Lean.Parser.Term.letIdDecl then
888
+ let { id, binders, type, value } := mkLetIdDeclView letDecl
889
+ let id ← if id.isIdent then pure id else mkFreshIdent id (canonical := true)
890
+ elabLetDeclAux id binders type value body expectedType? config
891
+ else if letDecl.getKind == ``Lean.Parser.Term.letPatDecl then
892
+ -- node `Lean.Parser.Term.letPatDecl $ try (termParser >> pushNone >> optType >> " := ") >> termParser
893
+ let pat := letDecl[0]
894
+ let optType := letDecl[2]
895
+ let val := letDecl[4]
896
+ if pat.getKind == ``Parser.Term.hole then
897
+ -- `let _ := ...` should be treated as a `letIdDecl`
898
+ let id ← mkFreshIdent pat (canonical := true)
899
+ let type := expandOptType id optType
900
+ elabLetDeclAux id #[] type val body expectedType? config
901
+ else
902
+ if config.postponeValue then
903
+ throwError "`+deferValue` with patterns is not allowed"
904
+ if config.usedOnly then
905
+ throwError "`+usedOnly` with patterns is not allowed"
906
+ if config.zeta then
907
+ throwError "`+zeta` with patterns is not allowed"
908
+ -- We are currently ignore `config.nondep` when patterns are used.
909
+ -- We are also currently ignoring `config.generalize`.
910
+ let val ← if optType.isNone then
911
+ `($val:term)
912
+ else
913
+ let type := optType[0][1]
914
+ `(($val:term : $type))
915
+ let stxNew ← if let some h := config.eq? then
916
+ `(match $h:ident : $val:term with | $pat => $body)
917
+ else
918
+ `(match $val:term with | $pat => $body)
919
+ withMacroExpansion stx stxNew <| elabTerm stxNew expectedType?
920
+ else if letDecl.getKind == ``Lean.Parser.Term.letEqnsDecl then
921
+ let letDeclIdNew ← liftMacroM <| expandLetEqnsDecl letDecl
922
+ let declNew := stx[declIdx].setArg 0 letDeclIdNew
923
+ let stxNew := stx.setArg declIdx declNew
924
+ withMacroExpansion stx stxNew <| elabTerm stxNew expectedType?
925
+ else
926
+ throwUnsupportedSyntax
927
+
928
+ @[builtin_term_elab Β«letΒ»] def elabLetDecl : TermElab :=
929
+ fun stx expectedType? => elabLetDeclCore stx expectedType? {}
930
+
931
+ @[builtin_term_elab Β«haveΒ»] def elabHaveDecl : TermElab :=
932
+ fun stx expectedType? => elabLetDeclCore stx expectedType? { nondep := true }
933
+
934
+ @[builtin_term_elab Β«let_funΒ»] def elabLetFunDecl : TermElab :=
935
+ fun stx expectedType? => do
936
+ withRef stx <| Linter.logLintIf Linter.linter.deprecated stx[0]
937
+ "`let_fun` has been deprecated in favor of `have`"
938
+ elabLetDeclCore stx expectedType? { nondep := true }
939
+
940
+ @[builtin_term_elab Β«let_delayedΒ»] def elabLetDelayedDecl : TermElab :=
941
+ fun stx expectedType? => elabLetDeclCore stx expectedType? { postponeValue := true }
942
+
943
+ @[builtin_term_elab Β«let_tmpΒ»] def elabLetTmpDecl : TermElab :=
944
+ fun stx expectedType? => elabLetDeclCore stx expectedType? { usedOnly := true }
945
+
946
+ @[builtin_term_elab Β«letIΒ»] def elabLetIDecl : TermElab :=
947
+ fun stx expectedType? => elabLetDeclCore stx expectedType? { zeta := true }
948
+
949
+ @[builtin_term_elab Β«haveIΒ»] def elabHaveIDecl : TermElab :=
950
+ fun stx expectedType? => elabLetDeclCore stx expectedType? { zeta := true, nondep := true }
951
+
952
+ builtin_initialize
953
+ registerTraceClass `Elab.let
954
+ registerTraceClass `Elab.let.decl
955
+ registerTraceClass `Elab.autoParam
956
+
957
+ end Lean.Elab.Term
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/BindersUtil.lean ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Parser.Term
8
+
9
+ namespace Lean.Elab.Term
10
+ /--
11
+ Recall that
12
+ ```
13
+ def typeSpec := leading_parser " : " >> termParser
14
+ def optType : Parser := optional typeSpec
15
+ ```
16
+ -/
17
+ def expandOptType (ref : Syntax) (optType : Syntax) : Syntax :=
18
+ if optType.isNone then
19
+ mkHole ref
20
+ else
21
+ optType[0][1]
22
+
23
+ open Lean.Parser.Term
24
+
25
+ /-- Helper function for `expandEqnsIntoMatch` -/
26
+ def getMatchAltsNumPatterns (matchAlts : Syntax) : Nat :=
27
+ let alt0 := matchAlts[0][0]
28
+ let pats := alt0[1][0].getSepArgs
29
+ pats.size
30
+
31
+ /--
32
+ Expand a match alternative such as `| 0 | 1 => rhs` to an array containing `| 0 => rhs` and `| 1 => rhs`.
33
+ -/
34
+ def expandMatchAlt (stx : TSyntax ``matchAlt) : MacroM (Array (TSyntax ``matchAlt)) :=
35
+ match stx with
36
+ | `(matchAltExpr| | $[$patss,*]|* => $rhs) =>
37
+ if patss.size ≀ 1 then
38
+ return #[stx]
39
+ else
40
+ patss.mapM fun pats => `(matchAltExpr| | $pats,* => $rhs)
41
+ | _ => return #[stx]
42
+
43
+ def shouldExpandMatchAlt : TSyntax ``matchAlt β†’ Bool
44
+ | `(matchAltExpr| | $[$patss,*]|* => $_) => patss.size > 1
45
+ | _ => false
46
+
47
+ def expandMatchAlts? (stx : Syntax) : MacroM (Option Syntax) := do
48
+ match stx with
49
+ | `(match $[$gen]? $[$motive]? $discrs,* with $alts:matchAlt*) =>
50
+ if alts.any shouldExpandMatchAlt then
51
+ let alts ← alts.foldlM (init := #[]) fun alts alt => return alts ++ (← expandMatchAlt alt)
52
+ `(match $[$gen]? $[$motive]? $discrs,* with $alts:matchAlt*)
53
+ else
54
+ return none
55
+ | _ => return none
56
+
57
+ open TSyntax.Compat in
58
+ def clearInMatchAlt (stx : TSyntax ``matchAlt) (vars : Array Ident) : TSyntax ``matchAlt :=
59
+ stx.1.modifyArg 3 fun rhs => Unhygienic.run do
60
+ let mut rhs := rhs
61
+ for v in vars do
62
+ rhs ← `(clear% $v; $rhs)
63
+ return rhs
64
+
65
+ def clearInMatch (stx : Syntax) (vars : Array Ident) : MacroM Syntax := do
66
+ if vars.isEmpty then return stx
67
+ match stx with
68
+ | `(match $[$gen]? $[$motive]? $discrs,* with $alts:matchAlt*) =>
69
+ let alts := alts.map (clearInMatchAlt Β· vars)
70
+ `(match $[$gen]? $[$motive]? $discrs,* with $alts:matchAlt*)
71
+ | _ => return stx
72
+
73
+ end Lean.Elab.Term
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/BuiltinCommand.lean ADDED
@@ -0,0 +1,676 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Util.CollectLevelParams
8
+ import Lean.Util.CollectAxioms
9
+ import Lean.Meta.Reduce
10
+ import Lean.Elab.DeclarationRange
11
+ import Lean.Elab.Eval
12
+ import Lean.Elab.Command
13
+ import Lean.Elab.Open
14
+ import Lean.Elab.SetOption
15
+ import Init.System.Platform
16
+ import Lean.Meta.Hint
17
+
18
+ namespace Lean.Elab.Command
19
+
20
+ @[builtin_command_elab moduleDoc] def elabModuleDoc : CommandElab := fun stx => do
21
+ match stx[1] with
22
+ | Syntax.atom _ val =>
23
+ let doc := val.extract 0 (val.endPos - ⟨2⟩)
24
+ let some range ← Elab.getDeclarationRange? stx
25
+ | return -- must be from partial syntax, ignore
26
+ modifyEnv fun env => addMainModuleDoc env ⟨doc, range⟩
27
+ | _ => throwErrorAt stx "unexpected module doc string{indentD stx[1]}"
28
+
29
+ private def addScope (isNewNamespace : Bool) (header : String) (newNamespace : Name)
30
+ (isNoncomputable isPublic : Bool := false) (attrs : List (TSyntax ``Parser.Term.attrInstance) := []) :
31
+ CommandElabM Unit := do
32
+ modify fun s => { s with
33
+ env := s.env.registerNamespace newNamespace,
34
+ scopes := { s.scopes.head! with
35
+ header := header, currNamespace := newNamespace
36
+ isNoncomputable := s.scopes.head!.isNoncomputable || isNoncomputable
37
+ isPublic := s.scopes.head!.isPublic || isPublic
38
+ attrs := s.scopes.head!.attrs ++ attrs
39
+ } :: s.scopes
40
+ }
41
+ pushScope
42
+ if isNewNamespace then
43
+ activateScoped newNamespace
44
+
45
+ private def addScopes (header : Name) (isNewNamespace : Bool) (isNoncomputable isPublic : Bool := false)
46
+ (attrs : List (TSyntax ``Parser.Term.attrInstance) := []) : CommandElabM Unit :=
47
+ go header
48
+ where go
49
+ | .anonymous => pure ()
50
+ | .str p header => do
51
+ go p
52
+ let currNamespace ← getCurrNamespace
53
+ addScope isNewNamespace header (if isNewNamespace then Name.mkStr currNamespace header else currNamespace) isNoncomputable isPublic attrs
54
+ | _ => throwError "invalid scope"
55
+
56
+ private def addNamespace (header : Name) : CommandElabM Unit :=
57
+ addScopes (isNewNamespace := true) (isNoncomputable := false) (attrs := []) header
58
+
59
+ def withNamespace {Ξ±} (ns : Name) (elabFn : CommandElabM Ξ±) : CommandElabM Ξ± := do
60
+ addNamespace ns
61
+ let a ← elabFn
62
+ modify fun s => { s with scopes := s.scopes.drop ns.getNumParts }
63
+ pure a
64
+
65
+ private def popScopes (numScopes : Nat) : CommandElabM Unit :=
66
+ for _ in [0:numScopes] do
67
+ popScope
68
+
69
+ private def innermostScopeName? : List Scope β†’ Option Name
70
+ | { header := "", .. } :: _ => none
71
+ | { header := h, .. } :: _ => some <| .mkSimple h
72
+ | _ => some .anonymous -- should not happen
73
+
74
+ private def checkEndHeader : Name β†’ List Scope β†’ Option Name
75
+ | .anonymous, _ => none
76
+ | .str p s, { header := h, .. } :: scopes =>
77
+ if h == s then
78
+ (.str Β· s) <$> checkEndHeader p scopes
79
+ else
80
+ some <| .mkSimple h
81
+ | _, _ => some .anonymous -- should not happen
82
+
83
+ @[builtin_command_elab Β«namespaceΒ»] def elabNamespace : CommandElab := fun stx =>
84
+ match stx with
85
+ | `(namespace $n) => addNamespace n.getId
86
+ | _ => throwUnsupportedSyntax
87
+
88
+ @[builtin_command_elab Β«sectionΒ»] def elabSection : CommandElab := fun stx => do
89
+ match stx with
90
+ | `(Parser.Command.section| $[public%$publicTk]? $[@[expose%$expTk]]? $[noncomputable%$ncTk]? section $(header?)?) =>
91
+ -- TODO: allow more attributes?
92
+ let attrs ← if expTk.isSome then
93
+ pure [← `(Parser.Term.attrInstance| expose)]
94
+ else
95
+ pure []
96
+ if let some header := header? then
97
+ addScopes (isNewNamespace := false) (isNoncomputable := ncTk.isSome) (isPublic := publicTk.isSome) (attrs := attrs) header.getId
98
+ else
99
+ addScope (isNewNamespace := false) (isNoncomputable := ncTk.isSome) (isPublic := publicTk.isSome) (attrs := attrs) "" (← getCurrNamespace)
100
+ | _ => throwUnsupportedSyntax
101
+
102
+ /--
103
+ Produces a `Name` composed of the names of at most the innermost `n` scopes in `ss`, truncating if an
104
+ empty scope is reached (so that we do not suggest names like `Foo.«».Bar`).
105
+
106
+ If `n` is not specified, will use all scopes in `ss`.
107
+ -/
108
+ private def nameOfScopes : (ss : List Scope) β†’ (n : Nat := ss.length) β†’ Name
109
+ | _, 0 => .anonymous
110
+ | [], _ => .anonymous
111
+ | s :: ss, n + 1 =>
112
+ if s.header == "" then
113
+ .anonymous
114
+ else
115
+ .str (nameOfScopes ss n) s.header
116
+
117
+ /--
118
+ Returns the first suffix of `base` that begins with `seg`, if one exists.
119
+
120
+ Note: this uses a naive, O(m*n) implementation for simplicity; we assume repeated partial overlap of
121
+ name components to be relatively uncommon, so that practical performance is closer to linear.
122
+ -/
123
+ private def findSuffixWithPrefix (base : Name) (seg : Name) : Option Name :=
124
+ findSuffixMatch base seg true
125
+ where
126
+ /--
127
+ Helper for `findSuffixWithPrefix`. If `allowOffset` is `false`, then `seg` must be a suffix of
128
+ `base`, not just a prefix of a suffix.
129
+ -/
130
+ findSuffixMatch : (base : Name) β†’ (seg : Name) β†’ (allowOffset : Bool) β†’ Option Name
131
+ | _, .anonymous, _ => some .anonymous
132
+ | .anonymous, _, _ => none
133
+ | .num p n, seg@(.num p' n'), allowOffset => do
134
+ if n == n' then
135
+ if let some nm := findSuffixMatch p p' (allowOffset := false) then
136
+ return .num nm n
137
+ if allowOffset then
138
+ return .num (← findSuffixMatch p seg allowOffset) n
139
+ else
140
+ none
141
+ | .str p s, seg@(.str p' s'), allowOffset => do
142
+ if s == s' then
143
+ if let some nm := findSuffixMatch p p' (allowOffset := false) then
144
+ return .str nm s
145
+ if allowOffset then
146
+ return .str (← findSuffixMatch p seg allowOffset) s
147
+ else
148
+ none
149
+ | .str p s, seg, allowOffset =>
150
+ if allowOffset then
151
+ return .str (← findSuffixMatch p seg allowOffset) s
152
+ else
153
+ none
154
+ | .num p n, seg, allowOffset =>
155
+ if allowOffset then
156
+ return .num (← findSuffixMatch p seg allowOffset) n
157
+ else
158
+ none
159
+
160
+ private def throwNoScope : CommandElabM Unit :=
161
+ throwError m!"Invalid `end`: There is no current scope to end"
162
+ ++ .note m!"Scopes are introduced using `namespace` and `section`"
163
+
164
+ private def throwMissingName (name : Name) : CommandElabM Unit := do
165
+ let hint ← liftCoreM <| MessageData.hint m!"To end the current scope `{name}`, specify its name:"
166
+ #[← `(end $(mkIdent name))] (codeActionPrefix? := "Add scope name: ")
167
+ throwError "Missing name after `end`: Expected the current scope name `{name}`{hint}"
168
+
169
+ /--
170
+ Produces a hint message with a suggestion to replace the name following `end` at the current ref
171
+ with the name given by `scopes` if there is only one active scope; otherwise, returns `none`.
172
+
173
+ Rationale: When there is only one active scope, only one valid `end` command is possible, so we
174
+ suggest it; if there are multiple, then it is harder to determine with confidence which the user
175
+ intended to end.
176
+ -/
177
+ private def mkSingleScopeReplacementHint? (scopes : List Scope) := do
178
+ -- Recall that there is always an anonymous topmost scope, so `scopes.length = 2` when there is
179
+ -- only one active scope:
180
+ if scopes.length == 2 then
181
+ let name := nameOfScopes scopes
182
+ some <$> MessageData.hint m!"Use current scope name `{name}`:" #[(← `(end $(mkIdent name)))]
183
+ (codeActionPrefix? := "Replace scope name: ")
184
+ else
185
+ return none
186
+
187
+ private def throwTooManyScopeComponents (header : Name) (scopes : List Scope) : CommandElabM Unit := do
188
+ let hint ← liftCoreM do
189
+ if let some hint ← mkSingleScopeReplacementHint? scopes then
190
+ pure hint
191
+ else
192
+ let scopesName := nameOfScopes scopes
193
+ pure <| MessageData.hint' m!"The name after `end` must be `{scopesName}` or some suffix thereof"
194
+ throwError m!"Invalid name after `end`: `{header}` contains too many components" ++ hint
195
+
196
+ private def throwScopeNameMismatch (header : Name) (scopes : List Scope) (endSize : Nat)
197
+ : CommandElabM Unit := do
198
+ let correspondingScopes := nameOfScopes scopes endSize
199
+ let allScopes := nameOfScopes scopes
200
+ let help ← liftCoreM do
201
+ if let some hint ← mkSingleScopeReplacementHint? scopes then
202
+ pure hint
203
+ else if let some suffix := findSuffixWithPrefix allScopes header then
204
+ let hintMsg := m!"If you meant to end the outer scope(s) `{header}`, you must end all the \
205
+ intervening scopes `{suffix}`:"
206
+ MessageData.hint hintMsg #[← `(end $(mkIdent suffix))]
207
+ (codeActionPrefix? := "Add intervening scopes: ")
208
+ else if correspondingScopes != allScopes then
209
+ pure <| .note m!"The current scopes are `{allScopes}`"
210
+ else pure .nil
211
+ throwError m!"Invalid name after `end`: Expected `{correspondingScopes}`, but found `{header}`" ++ help
212
+
213
+ private def throwUnnecessaryScopeName (header : Name) : CommandElabM Unit := do
214
+ let hintMsg := m!"Delete the name `{header}` to end the current unnamed scope; outer named scopes \
215
+ can then be closed using additional `end` command(s):"
216
+ let hint ← liftCoreM <| MessageData.hint hintMsg #[← `(end)] (codeActionPrefix? := "Delete name: ")
217
+ throwError m!"Unexpected name `{header}` after `end`: The current section is unnamed" ++ hint
218
+
219
+ @[builtin_command_elab Β«endΒ»] def elabEnd : CommandElab := fun stx => do
220
+ let header? := (stx.getArg 1).getOptionalIdent?
221
+ let endSize : Nat := match header? with
222
+ | none => 1
223
+ | some n => n.getNumParts
224
+ let scopes ← getScopes
225
+ let numScopes := scopes.length
226
+ if numScopes == 1 then
227
+ throwNoScope
228
+ match header? with
229
+ | none =>
230
+ if let some name := innermostScopeName? scopes then
231
+ throwMissingName name
232
+ | some header =>
233
+ if endSize >= numScopes then
234
+ throwTooManyScopeComponents header scopes
235
+ else
236
+ let scopesName := nameOfScopes scopes endSize
237
+ if scopesName != header then
238
+ if scopesName == .anonymous then
239
+ throwUnnecessaryScopeName header
240
+ else
241
+ throwScopeNameMismatch header scopes endSize
242
+ modify fun s => {s with scopes := s.scopes.drop endSize }
243
+ popScopes endSize
244
+
245
+ private partial def elabChoiceAux (cmds : Array Syntax) (i : Nat) : CommandElabM Unit :=
246
+ if h : i < cmds.size then
247
+ catchInternalId unsupportedSyntaxExceptionId
248
+ (elabCommand cmds[i])
249
+ (fun _ => elabChoiceAux cmds (i+1))
250
+ else
251
+ throwUnsupportedSyntax
252
+
253
+ @[builtin_command_elab choice] def elabChoice : CommandElab := fun stx =>
254
+ elabChoiceAux stx.getArgs 0
255
+
256
+ @[builtin_command_elab Β«universeΒ»] def elabUniverse : CommandElab := fun n => do
257
+ n[1].forArgsM addUnivLevel
258
+
259
+ @[builtin_command_elab Β«init_quotΒ»] def elabInitQuot : CommandElab := fun _ => do
260
+ liftCoreM <| addDecl Declaration.quotDecl
261
+
262
+ @[builtin_command_elab Β«exportΒ»] def elabExport : CommandElab := fun stx => do
263
+ let `(export $ns ($ids*)) := stx | throwUnsupportedSyntax
264
+ let nss ← resolveNamespace ns
265
+ let currNamespace ← getCurrNamespace
266
+ if nss == [currNamespace] then throwError "invalid 'export', self export"
267
+ let mut aliases := #[]
268
+ for idStx in ids do
269
+ let id := idStx.getId
270
+ let declName ← resolveNameUsingNamespaces nss idStx
271
+ if (← getInfoState).enabled then
272
+ addConstInfo idStx declName
273
+ aliases := aliases.push (currNamespace ++ id, declName)
274
+ modify fun s => { s with env := aliases.foldl (init := s.env) fun env p => addAlias env p.1 p.2 }
275
+
276
+ @[builtin_command_elab Β«openΒ»] def elabOpen : CommandElab
277
+ | `(open $decl:openDecl) => do
278
+ let openDecls ← elabOpenDecl decl
279
+ modifyScope fun scope => { scope with openDecls := openDecls }
280
+ | _ => throwUnsupportedSyntax
281
+
282
+ open Lean.Parser.Term
283
+
284
+ private def typelessBinder? : Syntax β†’ Option (Array (TSyntax [`ident, `Lean.Parser.Term.hole]) Γ— BinderInfo)
285
+ | `(bracketedBinderF|($ids*)) => some (ids, .default)
286
+ | `(bracketedBinderF|{$ids*}) => some (ids, .implicit)
287
+ | `(bracketedBinderF|⦃$ids*⦄) => some (ids, .strictImplicit)
288
+ | `(bracketedBinderF|[$id:ident]) => some (#[id], .instImplicit)
289
+ | _ => none
290
+
291
+ /-- If `id` is an identifier, return true if `ids` contains `id`. -/
292
+ private def containsId (ids : Array (TSyntax [`ident, ``Parser.Term.hole])) (id : TSyntax [`ident, ``Parser.Term.hole]) : Bool :=
293
+ id.raw.isIdent && ids.any fun id' => id'.raw.getId == id.raw.getId
294
+
295
+ /--
296
+ Auxiliary method for processing binder annotation update commands:
297
+ `variable (Ξ±)`, `variable {Ξ±}`, `variable ⦃α⦄`, and `variable [Ξ±]`.
298
+ The argument `binder` is the binder of the `variable` command.
299
+ The method returns an array containing the "residue", that is, variables that do not correspond to updates.
300
+ Recall that a `bracketedBinder` can be of the form `(x y)`.
301
+ ```
302
+ variable {Ξ± Ξ² : Type}
303
+ variable (Ξ± Ξ³)
304
+ ```
305
+ The second `variable` command updates the binder annotation for `Ξ±`, and returns "residue" `Ξ³`.
306
+ -/
307
+ private def replaceBinderAnnotation (binder : TSyntax ``Parser.Term.bracketedBinder) : CommandElabM (Array (TSyntax ``Parser.Term.bracketedBinder)) := do
308
+ let some (binderIds, binderInfo) := typelessBinder? binder | return #[binder]
309
+ let varDecls := (← getScope).varDecls
310
+ let mut varDeclsNew := #[]
311
+ let mut binderIds := binderIds
312
+ let mut binderIdsIniSize := binderIds.size
313
+ let mut modifiedVarDecls := false
314
+ -- Go through declarations in reverse to respect shadowing
315
+ for varDecl in varDecls.reverse do
316
+ let (ids, ty?, binderInfo') ← match varDecl with
317
+ | `(bracketedBinderF|($ids* $[: $ty?]? $(annot?)?)) =>
318
+ if annot?.isSome then
319
+ for binderId in binderIds do
320
+ if containsId ids binderId then
321
+ throwErrorAt binderId "cannot update binder annotation of variables with default values/tactics"
322
+ pure (ids, ty?, .default)
323
+ | `(bracketedBinderF|{$ids* $[: $ty?]?}) =>
324
+ pure (ids, ty?, .implicit)
325
+ | `(bracketedBinderF|⦃$ids* $[: $ty?]?⦄) =>
326
+ pure (ids, ty?, .strictImplicit)
327
+ | `(bracketedBinderF|[$id : $ty]) =>
328
+ pure (#[⟨id⟩], some ty, .instImplicit)
329
+ | _ =>
330
+ varDeclsNew := varDeclsNew.push varDecl; continue
331
+ if binderInfo == binderInfo' then
332
+ -- no update, ensure we don't have redundant annotations.
333
+ for binderId in binderIds do
334
+ if containsId ids binderId then
335
+ throwErrorAt binderId "redundant binder annotation update"
336
+ varDeclsNew := varDeclsNew.push varDecl
337
+ else if binderIds.all fun binderId => !containsId ids binderId then
338
+ -- `binderIds` and `ids` are disjoint
339
+ varDeclsNew := varDeclsNew.push varDecl
340
+ else
341
+ let mkBinder (id : TSyntax [`ident, ``Parser.Term.hole]) (binderInfo : BinderInfo) : CommandElabM (TSyntax ``Parser.Term.bracketedBinder) :=
342
+ match binderInfo with
343
+ | .default => `(bracketedBinderF| ($id $[: $ty?]?))
344
+ | .implicit => `(bracketedBinderF| {$id $[: $ty?]?})
345
+ | .strictImplicit => `(bracketedBinderF| {{$id $[: $ty?]?}})
346
+ | .instImplicit => do
347
+ let some ty := ty?
348
+ | throwErrorAt binder "cannot update binder annotation of variable '{id}' to instance implicit:\n\
349
+ variable was originally declared without an explicit type"
350
+ `(bracketedBinderF| [$(⟨id⟩) : $ty])
351
+ for id in ids.reverse do
352
+ if let some idx := binderIds.findFinIdx? fun binderId => binderId.raw.isIdent && binderId.raw.getId == id.raw.getId then
353
+ binderIds := binderIds.eraseIdx idx
354
+ modifiedVarDecls := true
355
+ let newBinder ← mkBinder id binderInfo
356
+ if binderInfo.isInstImplicit then
357
+ -- We elaborate the new binder to make sure it's valid as instance implicit
358
+ try
359
+ runTermElabM fun _ => Term.withSynthesize <| Term.withAutoBoundImplicit <|
360
+ Term.elabBinder newBinder fun _ => pure ()
361
+ catch e =>
362
+ throwErrorAt binder m!"cannot update binder annotation of variable '{id}' to instance implicit:\n\
363
+ {e.toMessageData}"
364
+ varDeclsNew := varDeclsNew.push (← mkBinder id binderInfo)
365
+ else
366
+ varDeclsNew := varDeclsNew.push (← mkBinder id binderInfo')
367
+ if modifiedVarDecls then
368
+ modifyScope fun scope => { scope with varDecls := varDeclsNew.reverse }
369
+ if binderIds.size != binderIdsIniSize then
370
+ binderIds.mapM fun binderId =>
371
+ match binderInfo with
372
+ | .default => `(bracketedBinderF| ($binderId))
373
+ | .implicit => `(bracketedBinderF| {$binderId})
374
+ | .strictImplicit => `(bracketedBinderF| {{$binderId}})
375
+ | .instImplicit => throwUnsupportedSyntax
376
+ else
377
+ return #[binder]
378
+
379
+ @[builtin_command_elab Β«variableΒ»] def elabVariable : CommandElab
380
+ | `(variable%$tk $binders*) => do
381
+ let binders ← binders.flatMapM replaceBinderAnnotation
382
+ -- Try to elaborate `binders` for sanity checking
383
+ runTermElabM fun _ => Term.withSynthesize <| Term.withAutoBoundImplicit <|
384
+ Term.elabBinders binders fun xs => do
385
+ -- Determine the set of auto-implicits for this variable command and add an inlay hint
386
+ -- for them. We will only actually add the auto-implicits to a type when the variables
387
+ -- declared here are used in some other declaration, but this is nonetheless the right
388
+ -- place to display the inlay hint.
389
+ let _ ← Term.addAutoBoundImplicits xs (tk.getTailPos? (canonicalOnly := true))
390
+ -- Remark: if we want to produce error messages when variables shadow existing ones, here is the place to do it.
391
+ for binder in binders do
392
+ let varUIds ← (← getBracketedBinderIds binder) |>.mapM (withFreshMacroScope ∘ MonadQuotation.addMacroScope)
393
+ modifyScope fun scope => { scope with varDecls := scope.varDecls.push binder, varUIds := scope.varUIds ++ varUIds }
394
+ | _ => throwUnsupportedSyntax
395
+
396
+ open Meta
397
+
398
+ def elabCheckCore (ignoreStuckTC : Bool) : CommandElab
399
+ | `(#check%$tk $term) => withoutModifyingEnv <| runTermElabM fun _ => Term.withDeclName `_check do
400
+ -- show signature for `#check id`/`#check @id`
401
+ if let `($id:ident) := term then
402
+ try
403
+ for c in (← realizeGlobalConstWithInfos term) do
404
+ addCompletionInfo <| .id term id.getId (danglingDot := false) {} none
405
+ logInfoAt tk <| .signature c
406
+ return
407
+ catch _ => pure () -- identifier might not be a constant but constant + projection
408
+ let e ← Term.elabTerm term none
409
+ Term.synthesizeSyntheticMVarsNoPostponing (ignoreStuckTC := ignoreStuckTC)
410
+ -- Users might be testing out buggy elaborators. Let's typecheck before proceeding:
411
+ withRef tk <| Meta.check e
412
+ let e ← Term.levelMVarToParam (← instantiateMVars e)
413
+ if e.isSyntheticSorry then
414
+ return
415
+ let type ← inferType e
416
+ logInfoAt tk m!"{e} : {type}"
417
+ | _ => throwUnsupportedSyntax
418
+
419
+ @[builtin_command_elab Lean.Parser.Command.check] def elabCheck : CommandElab := elabCheckCore (ignoreStuckTC := true)
420
+
421
+ @[builtin_command_elab Lean.reduceCmd] def elabReduce : CommandElab
422
+ | `(#reduce%$tk $term) => go tk term
423
+ | `(#reduce%$tk (proofs := true) $term) => go tk term (skipProofs := false)
424
+ | `(#reduce%$tk (types := true) $term) => go tk term (skipTypes := false)
425
+ | `(#reduce%$tk (proofs := true) (types := true) $term) => go tk term (skipProofs := false) (skipTypes := false)
426
+ | _ => throwUnsupportedSyntax
427
+ where
428
+ go (tk : Syntax) (term : Syntax) (skipProofs := true) (skipTypes := true) : CommandElabM Unit :=
429
+ withoutModifyingEnv <| runTermElabM fun _ => Term.withDeclName `_reduce do
430
+ let e ← Term.elabTerm term none
431
+ Term.synthesizeSyntheticMVarsNoPostponing
432
+ -- Users might be testing out buggy elaborators. Let's typecheck before proceeding:
433
+ withRef tk <| Meta.check e
434
+ let e ← Term.levelMVarToParam (← instantiateMVars e)
435
+ -- TODO: add options or notation for setting the following parameters
436
+ withTheReader Core.Context (fun ctx => { ctx with options := ctx.options.setBool `smartUnfolding false }) do
437
+ let e ← withTransparency (mode := TransparencyMode.all) <| reduce e (skipProofs := skipProofs) (skipTypes := skipTypes)
438
+ logInfoAt tk e
439
+
440
+ def hasNoErrorMessages : CommandElabM Bool := do
441
+ return !(← get).messages.hasErrors
442
+
443
+ def failIfSucceeds (x : CommandElabM Unit) : CommandElabM Unit := do
444
+ let resetMessages : CommandElabM MessageLog := do
445
+ let s ← get
446
+ let messages := s.messages;
447
+ modify fun s => { s with messages := {} };
448
+ pure messages
449
+ let restoreMessages (prevMessages : MessageLog) : CommandElabM Unit := do
450
+ modify fun s => { s with messages := prevMessages ++ s.messages.errorsToInfos }
451
+ let prevMessages ← resetMessages
452
+ let succeeded ← try
453
+ x
454
+ hasNoErrorMessages
455
+ catch
456
+ | ex@(Exception.error _ _) => do logException ex; pure false
457
+ | Exception.internal id _ => do logError (← id.getName); pure false
458
+ finally
459
+ restoreMessages prevMessages
460
+ if succeeded then
461
+ throwError "unexpected success"
462
+
463
+ @[builtin_command_elab Β«check_failureΒ»] def elabCheckFailure : CommandElab
464
+ | `(#check_failure $term) => do
465
+ failIfSucceeds <| elabCheckCore (ignoreStuckTC := false) (← `(#check $term))
466
+ | _ => throwUnsupportedSyntax
467
+
468
+ @[builtin_command_elab Β«synthΒ»] def elabSynth : CommandElab := fun stx => do
469
+ let term := stx[1]
470
+ withoutModifyingEnv <| runTermElabM fun _ => Term.withDeclName `_synth_cmd do
471
+ let inst ← Term.elabTerm term none
472
+ Term.synthesizeSyntheticMVarsNoPostponing
473
+ let inst ← instantiateMVars inst
474
+ let val ← synthInstance inst
475
+ logInfo val
476
+ pure ()
477
+
478
+ @[builtin_command_elab Β«set_optionΒ»] def elabSetOption : CommandElab := fun stx => do
479
+ let options ← Elab.elabSetOption stx[1] stx[3]
480
+ modify fun s => { s with maxRecDepth := maxRecDepth.get options }
481
+ modifyScope fun scope => { scope with opts := options }
482
+
483
+ @[builtin_macro Lean.Parser.Command.Β«inΒ»] def expandInCmd : Macro
484
+ | `($cmd₁ in%$tk $cmdβ‚‚) =>
485
+ -- Limit ref variability for incrementality; see Note [Incremental Macros]
486
+ withRef tk `(section $cmd₁:command $cmdβ‚‚ end)
487
+ | _ => Macro.throwUnsupported
488
+
489
+ @[builtin_command_elab Parser.Command.addDocString] def elabAddDeclDoc : CommandElab := fun stx => do
490
+ match stx with
491
+ | `($doc:docComment add_decl_doc $id) =>
492
+ let declName ← liftCoreM <| realizeGlobalConstNoOverloadWithInfo id
493
+ unless ((← getEnv).getModuleIdxFor? declName).isNone do
494
+ throwError "invalid 'add_decl_doc', declaration is in an imported module"
495
+ if let .none ← findDeclarationRangesCore? declName then
496
+ -- this is only relevant for declarations added without a declaration range
497
+ -- in particular `Quot.mk` et al which are added by `init_quot`
498
+ addDeclarationRangesFromSyntax declName stx id
499
+ addDocString declName doc
500
+ | _ => throwUnsupportedSyntax
501
+
502
+ @[builtin_command_elab Lean.Parser.Command.include] def elabInclude : CommandElab
503
+ | `(Lean.Parser.Command.include| include $ids*) => do
504
+ let sc ← getScope
505
+ let vars ← sc.varDecls.flatMapM getBracketedBinderIds
506
+ let mut uids := #[]
507
+ for id in ids do
508
+ if let some idx := vars.findIdx? (Β· == id.getId) then
509
+ uids := uids.push sc.varUIds[idx]!
510
+ else
511
+ throwError "invalid 'include', variable '{id}' has not been declared in the current scope"
512
+ modifyScope fun sc => { sc with
513
+ includedVars := sc.includedVars ++ uids.toList
514
+ omittedVars := sc.omittedVars.filter (!uids.contains Β·) }
515
+ | _ => throwUnsupportedSyntax
516
+
517
+ @[builtin_command_elab Lean.Parser.Command.omit] def elabOmit : CommandElab
518
+ | `(Lean.Parser.Command.omit| omit $omits*) => do
519
+ -- TODO: this really shouldn't have to re-elaborate section vars... they should come
520
+ -- pre-elaborated
521
+ let omittedVars ← runTermElabM fun vars => do
522
+ Term.synthesizeSyntheticMVarsNoPostponing
523
+ -- We don't want to store messages produced when elaborating `(getVarDecls s)` because they have already been saved when we elaborated the `variable`(s) command.
524
+ -- So, we use `Core.resetMessageLog`.
525
+ Core.resetMessageLog
526
+ -- resolve each omit to variable user name or type pattern
527
+ let elaboratedOmits : Array (Sum Name Expr) ← omits.mapM fun
528
+ | `(ident| $id:ident) => pure <| Sum.inl id.getId
529
+ | `(Lean.Parser.Term.instBinder| [$id : $_]) => pure <| Sum.inl id.getId
530
+ | `(Lean.Parser.Term.instBinder| [$ty]) =>
531
+ Sum.inr <$> Term.withoutErrToSorry (Term.elabTermAndSynthesize ty none)
532
+ | _ => throwUnsupportedSyntax
533
+ -- check that each omit is actually used in the end
534
+ let mut omitsUsed := omits.map fun _ => false
535
+ let mut omittedVars := #[]
536
+ let mut revSectionFVars : Std.HashMap FVarId Name := {}
537
+ for (uid, var) in (← read).sectionFVars do
538
+ revSectionFVars := revSectionFVars.insert var.fvarId! uid
539
+ for var in vars do
540
+ let ldecl ← var.fvarId!.getDecl
541
+ if let some idx := (← elaboratedOmits.findIdxM? fun
542
+ | .inl id => return ldecl.userName == id
543
+ | .inr ty => do
544
+ let mctx ← getMCtx
545
+ isDefEq ty ldecl.type <* setMCtx mctx) then
546
+ if let some uid := revSectionFVars[var.fvarId!]? then
547
+ omittedVars := omittedVars.push uid
548
+ omitsUsed := omitsUsed.set! idx true
549
+ else
550
+ throwError "invalid 'omit', '{ldecl.userName}' has not been declared in the current scope"
551
+ for o in omits, used in omitsUsed do
552
+ unless used do
553
+ throwError "'{o}' did not match any variables in the current scope"
554
+ return omittedVars
555
+ modifyScope fun sc => { sc with
556
+ omittedVars := sc.omittedVars ++ omittedVars.toList
557
+ includedVars := sc.includedVars.filter (!omittedVars.contains Β·) }
558
+ | _ => throwUnsupportedSyntax
559
+
560
+ @[builtin_command_elab version] def elabVersion : CommandElab := fun _ => do
561
+ let mut target := System.Platform.target
562
+ if target.isEmpty then target := "unknown"
563
+ -- Only one should be set, but good to know if multiple are set in error.
564
+ let platforms :=
565
+ (if System.Platform.isWindows then [" Windows"] else [])
566
+ ++ (if System.Platform.isOSX then [" macOS"] else [])
567
+ ++ (if System.Platform.isEmscripten then [" Emscripten"] else [])
568
+ logInfo m!"Lean {Lean.versionString}\nTarget: {target}{String.join platforms}"
569
+
570
+ @[builtin_command_elab Parser.Command.exit] def elabExit : CommandElab := fun _ =>
571
+ logWarning "using 'exit' to interrupt Lean"
572
+
573
+ @[builtin_command_elab Parser.Command.import] def elabImport : CommandElab := fun _ =>
574
+ throwError "invalid 'import' command, it must be used in the beginning of the file"
575
+
576
+ @[builtin_command_elab Parser.Command.eoi] def elabEoi : CommandElab := fun _ =>
577
+ return
578
+
579
+ @[builtin_command_elab Parser.Command.where] def elabWhere : CommandElab := fun _ => do
580
+ let scope ← getScope
581
+ let mut msg : Array MessageData := #[]
582
+ -- Noncomputable
583
+ if scope.isNoncomputable then
584
+ msg := msg.push <| ← `(Parser.Command.section| noncomputable section)
585
+ -- Namespace
586
+ if !scope.currNamespace.isAnonymous then
587
+ msg := msg.push <| ← `(command| namespace $(mkIdent scope.currNamespace))
588
+ -- Open namespaces
589
+ if let some openMsg ← describeOpenDecls scope.openDecls.reverse then
590
+ msg := msg.push openMsg
591
+ -- Universe levels
592
+ if !scope.levelNames.isEmpty then
593
+ let levels := scope.levelNames.reverse.map mkIdent
594
+ msg := msg.push <| ← `(command| universe $levels.toArray*)
595
+ -- Variables
596
+ if !scope.varDecls.isEmpty then
597
+ let varDecls : Array (TSyntax `Lean.Parser.Term.bracketedBinder) := scope.varDecls.map (⟨·.raw.unsetTrailing⟩)
598
+ msg := msg.push <| ← `(command| variable $varDecls*)
599
+ -- Included variables
600
+ if !scope.includedVars.isEmpty then
601
+ msg := msg.push <| ← `(command| include $(scope.includedVars.toArray.map (mkIdent Β·.eraseMacroScopes))*)
602
+ -- Options
603
+ if let some optionsMsg ← describeOptions scope.opts then
604
+ msg := msg.push optionsMsg
605
+ if msg.isEmpty then
606
+ logInfo m!"-- In root namespace with initial scope"
607
+ else
608
+ logInfo <| MessageData.joinSep msg.toList "\n\n"
609
+ where
610
+ /--
611
+ 'Delaborate' open declarations.
612
+ Current limitations:
613
+ - does not check whether or not successive namespaces need `_root_`
614
+ - does not combine commands with `renaming` clauses into a single command
615
+ -/
616
+ describeOpenDecls (ds : List OpenDecl) : CommandElabM (Option MessageData) := do
617
+ let mut lines : Array MessageData := #[]
618
+ let mut simple : Array Name := #[]
619
+ let flush (lines : Array MessageData) (simple : Array Name) : CommandElabM (Array MessageData Γ— Array Name) := do
620
+ if simple.isEmpty then
621
+ return (lines, simple)
622
+ else
623
+ return (lines.push <| ← `(command| open $(simple.map mkIdent)*), #[])
624
+ for d in ds do
625
+ match d with
626
+ | .explicit id decl =>
627
+ (lines, simple) ← flush lines simple
628
+ let ns := decl.getPrefix
629
+ let Β«fromΒ» := Name.mkSimple decl.getString!
630
+ lines := lines.push <| ← `(command| open $(mkIdent ns) renaming $(mkIdent Β«fromΒ») β†’ $(mkIdent id))
631
+ | .simple ns ex =>
632
+ if ex == [] then
633
+ simple := simple.push ns
634
+ else
635
+ (lines, simple) ← flush lines simple
636
+ lines := lines.push <| ← `(command| open $(mkIdent ns) hiding $[$(ex.toArray.map mkIdent)]*)
637
+ (lines, _) ← flush lines simple
638
+ return if lines.isEmpty then none else MessageData.joinSep lines.toList "\n"
639
+
640
+ describeOptions (opts : Options) : CommandElabM (Option MessageData) := do
641
+ let mut lines : Array MessageData := #[]
642
+ let decls ← getOptionDecls
643
+ for (name, val) in opts do
644
+ -- `#guard_msgs` sets this option internally, we don't want it to end up in its output
645
+ if name == `Elab.async then
646
+ continue
647
+ let (isSet, isUnknown) :=
648
+ match decls.find? name with
649
+ | some decl => (decl.defValue != val, false)
650
+ | none => (true, true)
651
+ if isSet then
652
+ let cmd : TSyntax `command ←
653
+ match val with
654
+ | .ofBool true => `(set_option $(mkIdent name) true)
655
+ | .ofBool false => `(set_option $(mkIdent name) false)
656
+ | .ofString str => `(set_option $(mkIdent name) $(Syntax.mkStrLit str))
657
+ | .ofNat n => `(set_option $(mkIdent name) $(Syntax.mkNatLit n))
658
+ | _ => `(set_option $(mkIdent name) 0 /- unrepresentable value -/)
659
+ if isUnknown then
660
+ lines := lines.push m!"-- {cmd} -- unknown option"
661
+ else
662
+ lines := lines.push cmd
663
+ return if lines.isEmpty then none else MessageData.joinSep lines.toList "\n"
664
+
665
+ @[builtin_command_elab Parser.Command.withExporting] def elabWithExporting : CommandElab
666
+ | `(Parser.Command.withExporting| #with_exporting $cmd) =>
667
+ withExporting do
668
+ elabCommand cmd
669
+ | _ => throwUnsupportedSyntax
670
+
671
+ @[builtin_command_elab Parser.Command.dumpAsyncEnvState] def elabDumpAsyncEnvState : CommandElab :=
672
+ fun _ => do
673
+ let env ← getEnv
674
+ IO.eprintln (← env.dbgFormatAsyncState)
675
+
676
+ end Lean.Elab.Command
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/BuiltinEvalCommand.lean ADDED
@@ -0,0 +1,277 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Kyle Miller
5
+ -/
6
+ prelude
7
+ import Lean.Util.CollectAxioms
8
+ import Lean.Elab.Deriving.Basic
9
+ import Lean.Elab.MutualDef
10
+
11
+ /-!
12
+ # Implementation of `#eval` command
13
+ -/
14
+
15
+ namespace Lean.Elab.Command
16
+ open Meta
17
+
18
+ register_builtin_option eval.pp : Bool := {
19
+ defValue := true
20
+ descr := "('#eval' command) enables using 'ToExpr' instances to pretty print the result, \
21
+ otherwise uses 'Repr' or 'ToString' instances"
22
+ }
23
+
24
+ register_builtin_option eval.type : Bool := {
25
+ defValue := false -- TODO: set to 'true'
26
+ descr := "('#eval' command) enables pretty printing the type of the result"
27
+ }
28
+
29
+ register_builtin_option eval.derive.repr : Bool := {
30
+ defValue := true
31
+ descr := "('#eval' command) enables auto-deriving 'Repr' instances as a fallback"
32
+ }
33
+
34
+ builtin_initialize
35
+ registerTraceClass `Elab.eval
36
+
37
+ /--
38
+ Elaborates the term, ensuring the result has no expression metavariables.
39
+ If there would be unsolved-for metavariables, tries hinting that the resulting type
40
+ is a monadic value with the `CommandElabM`, `TermElabM`, or `IO` monads.
41
+ Throws errors if the term is a proof or a type, but lifts props to `Bool` using `mkDecide`.
42
+ -/
43
+ private def elabTermForEval (term : Syntax) (expectedType? : Option Expr) : TermElabM Expr := do
44
+ let ty ← expectedType?.getDM mkFreshTypeMVar
45
+ let e ← Term.elabTermEnsuringType term ty
46
+ synthesizeWithHinting ty
47
+ let e ← instantiateMVars e
48
+ if (← Term.logUnassignedUsingErrorInfos (← getMVars e)) then throwAbortTerm
49
+ if ← isProof e then
50
+ throwError m!"cannot evaluate, proofs are not computationally relevant"
51
+ let e ← if (← isProp e) then mkDecide e else pure e
52
+ if ← isType e then
53
+ throwError m!"cannot evaluate, types are not computationally relevant"
54
+ trace[Elab.eval] "elaborated term:{indentExpr e}"
55
+ return e
56
+ where
57
+ /-- Try different strategies to make `Term.synthesizeSyntheticMVarsNoPostponing` succeed. -/
58
+ synthesizeWithHinting (ty : Expr) : TermElabM Unit := do
59
+ Term.synthesizeSyntheticMVarsUsingDefault
60
+ let s ← saveState
61
+ try
62
+ Term.synthesizeSyntheticMVarsNoPostponing
63
+ catch ex =>
64
+ let exS ← saveState
65
+ -- Try hinting that `ty` is a monad application.
66
+ for m in #[``CommandElabM, ``TermElabM, ``IO] do
67
+ s.restore true
68
+ try
69
+ if ← isDefEq ty (← mkFreshMonadApp m) then
70
+ Term.synthesizeSyntheticMVarsNoPostponing
71
+ return
72
+ catch _ => pure ()
73
+ -- None of the hints worked, so throw the original error.
74
+ exS.restore true
75
+ throw ex
76
+ mkFreshMonadApp (n : Name) : MetaM Expr := do
77
+ let m ← mkConstWithFreshMVarLevels n
78
+ let (args, _, _) ← forallMetaBoundedTelescope (← inferType m) 1
79
+ return mkAppN m args
80
+
81
+ private def addAndCompileExprForEval (declName : Name) (value : Expr) (allowSorry := false) : TermElabM Unit := do
82
+ -- Use the `elabMutualDef` machinery to be able to support `let rec`.
83
+ -- Hack: since we are using the `TermElabM` version, we can insert the `value` as a metavariable via `exprToSyntax`.
84
+ -- An alternative design would be to make `elabTermForEval` into a term elaborator and elaborate the command all at once
85
+ -- with `unsafe def _eval := term_for_eval% $t`, which we did try, but unwanted error messages
86
+ -- such as "failed to infer definition type" can surface.
87
+ let defView := mkDefViewOfDef { isUnsafe := true }
88
+ (← `(Parser.Command.definition|
89
+ def $(mkIdent <| `_root_ ++ declName) := $(← Term.exprToSyntax value)))
90
+ Term.elabMutualDef #[] { header := "" } #[defView]
91
+ unless allowSorry do
92
+ let axioms ← collectAxioms declName
93
+ if axioms.contains ``sorryAx then
94
+ throwError "\
95
+ aborting evaluation since the expression depends on the 'sorry' axiom, \
96
+ which can lead to runtime instability and crashes.\n\n\
97
+ To attempt to evaluate anyway despite the risks, use the '#eval!' command."
98
+
99
+ /--
100
+ Try to make a `@projFn ty inst e` application, even if it takes unfolding the type `ty` of `e` to synthesize the instance `inst`.
101
+ -/
102
+ private partial def mkDeltaInstProj (inst projFn : Name) (e : Expr) (ty? : Option Expr := none) (tryReduce : Bool := true) : MetaM Expr := do
103
+ let ty ← ty?.getDM (inferType e)
104
+ if let .some inst ← trySynthInstance (← mkAppM inst #[ty]) then
105
+ mkAppOptM projFn #[ty, inst, e]
106
+ else
107
+ let ty ← whnfCore ty
108
+ let some ty ← unfoldDefinition? ty
109
+ | guard tryReduce
110
+ -- Reducing the type is a strategy `#eval` used before the refactor of #5627.
111
+ -- The test lean/run/hlistOverload.lean depends on it, so we preserve the behavior.
112
+ let ty ← reduce (skipTypes := false) ty
113
+ mkDeltaInstProj inst projFn e ty (tryReduce := false)
114
+ mkDeltaInstProj inst projFn e ty tryReduce
115
+
116
+ /-- Try to make a `toString e` application, even if it takes unfolding the type of `e` to find a `ToString` instance. -/
117
+ private def mkToString (e : Expr) (ty? : Option Expr := none) : MetaM Expr := do
118
+ mkDeltaInstProj ``ToString ``toString e ty?
119
+
120
+ /-- Try to make a `repr e` application, even if it takes unfolding the type of `e` to find a `Repr` instance. -/
121
+ private def mkRepr (e : Expr) (ty? : Option Expr := none) : MetaM Expr := do
122
+ mkDeltaInstProj ``Repr ``repr e ty?
123
+
124
+ /-- Try to make a `toExpr e` application, even if it takes unfolding the type of `e` to find a `ToExpr` instance. -/
125
+ private def mkToExpr (e : Expr) (ty? : Option Expr := none) : MetaM Expr := do
126
+ mkDeltaInstProj ``ToExpr ``toExpr e ty?
127
+
128
+ /--
129
+ Returns a representation of `e` using `Format`, or else fails.
130
+ If the `eval.derive.repr` option is true, then tries automatically deriving a `Repr` instance first.
131
+ Currently auto-derivation does not attempt to derive recursively.
132
+ -/
133
+ private def mkFormat (e : Expr) : MetaM Expr := do
134
+ mkRepr e <|> (do mkAppM ``Std.Format.text #[← mkToString e])
135
+ <|> do
136
+ if eval.derive.repr.get (← getOptions) then
137
+ if let .const name _ := (← whnf (← inferType e)).getAppFn then
138
+ try
139
+ trace[Elab.eval] "Attempting to derive a 'Repr' instance for '{.ofConstName name}'"
140
+ liftCommandElabM do applyDerivingHandlers ``Repr #[name]
141
+ resetSynthInstanceCache
142
+ return ← mkRepr e
143
+ catch ex =>
144
+ trace[Elab.eval] "Failed to use derived 'Repr' instance. Exception: {ex.toMessageData}"
145
+ throwError m!"could not synthesize a 'Repr' or 'ToString' instance for type{indentExpr (← inferType e)}"
146
+
147
+ /--
148
+ Returns a representation of `e` using `MessageData`, or else fails.
149
+ Tries `mkFormat` if a `ToExpr` instance can't be synthesized.
150
+ -/
151
+ private def mkMessageData (e : Expr) : MetaM Expr := do
152
+ (do guard <| eval.pp.get (← getOptions); mkAppM ``MessageData.ofExpr #[← mkToExpr e])
153
+ <|> (return mkApp (mkConst ``MessageData.ofFormat) (← mkFormat e))
154
+ <|> do throwError m!"could not synthesize a 'ToExpr', 'Repr', or 'ToString' instance for type{indentExpr (← inferType e)}"
155
+
156
+ private structure EvalAction where
157
+ eval : CommandElabM MessageData
158
+ /-- Whether to print the result of evaluation.
159
+ If `some`, the expression is what type to use for the type ascription when `pp.type` is true. -/
160
+ printVal : Option Expr
161
+
162
+ unsafe def elabEvalCoreUnsafe (bang : Bool) (tk term : Syntax) (expectedType? : Option Expr) : CommandElabM Unit := withRef tk do
163
+ let declName := `_eval
164
+ -- `t` is either `MessageData` or `Format`, and `mkT` is for synthesizing an expression that yields a `t`.
165
+ -- The `toMessageData` function adapts `t` to `MessageData`.
166
+ let mkAct {t : Type} [Inhabited t] (toMessageData : t β†’ MessageData) (mkT : Expr β†’ MetaM Expr) (e : Expr) : TermElabM EvalAction := do
167
+ -- Create a monadic action given the name of the monad `mc`, the monad `m` itself,
168
+ -- and an expression `e` to evaluate in this monad.
169
+ -- A trick here is that `mkMAct?` makes use of `MonadEval` instances are currently available in this stage,
170
+ -- and we do not need them to be available in the target environment.
171
+ let mkMAct? (mc : Name) (m : Type β†’ Type) [Monad m] [MonadEvalT m CommandElabM] (e : Expr) : TermElabM (Option EvalAction) := do
172
+ let some e ← observing? (mkAppOptM ``MonadEvalT.monadEval #[none, mkConst mc, none, none, e])
173
+ | return none
174
+ let eType := e.appFn!.appArg!
175
+ if ← isDefEq eType (mkConst ``Unit) then
176
+ addAndCompileExprForEval declName e (allowSorry := bang)
177
+ let mf : m Unit ← evalConst (m Unit) declName
178
+ return some { eval := do MonadEvalT.monadEval mf; pure "", printVal := none }
179
+ else
180
+ let rf ← withLocalDeclD `x eType fun x => do mkLambdaFVars #[x] (← mkT x)
181
+ let r ← mkAppM ``Functor.map #[rf, e]
182
+ addAndCompileExprForEval declName r (allowSorry := bang)
183
+ let mf : m t ← evalConst (m t) declName
184
+ return some { eval := toMessageData <$> MonadEvalT.monadEval mf, printVal := some eType }
185
+ if let some act ← mkMAct? ``CommandElabM CommandElabM e
186
+ -- Fallbacks in case we are in the Lean package but don't have `CommandElabM` yet
187
+ <||> mkMAct? ``TermElabM TermElabM e <||> mkMAct? ``MetaM MetaM e <||> mkMAct? ``CoreM CoreM e
188
+ -- Fallback in case nothing is imported
189
+ <||> mkMAct? ``IO IO e then
190
+ return act
191
+ else
192
+ -- Otherwise, assume this is a pure value.
193
+ -- There is no need to adapt pure values to `CommandElabM`.
194
+ -- This enables `#eval` to work on pure values even when `CommandElabM` is not available.
195
+ let r ← try mkT e catch ex => do
196
+ -- Diagnose whether the value is monadic for a representable value, since it's better to mention `MonadEval` in that case.
197
+ try
198
+ let some (m, ty) ← isTypeApp? (← inferType e) | failure
199
+ guard <| (← isMonad? m).isSome
200
+ -- Verify that there is a way to form some representation:
201
+ discard <| withLocalDeclD `x ty fun x => mkT x
202
+ catch _ =>
203
+ throw ex
204
+ throwError m!"unable to synthesize '{.ofConstName ``MonadEval}' instance \
205
+ to adapt{indentExpr (← inferType e)}\n\
206
+ to '{.ofConstName ``IO}' or '{.ofConstName ``CommandElabM}'."
207
+ addAndCompileExprForEval declName r (allowSorry := bang)
208
+ -- `evalConst` may emit IO, but this is collected by `withIsolatedStreams` below.
209
+ let r ← toMessageData <$> evalConst t declName (checkMeta := !Elab.inServer.get (← getOptions))
210
+ return { eval := pure r, printVal := some (← inferType e) }
211
+ let (output, exOrRes) ← IO.FS.withIsolatedStreams (isolateStderr := Core.stderrAsMessages.get (← getOptions)) do
212
+ try
213
+ -- Generate an action without executing it. We use `withoutModifyingEnv` to ensure
214
+ -- we don't pollute the environment with auxiliary declarations.
215
+ let act : EvalAction ← liftTermElabM do Term.withDeclName declName do withoutModifyingEnv do
216
+ let e ← elabTermForEval term expectedType?
217
+ -- If there is an elaboration error, don't evaluate!
218
+ if e.hasSyntheticSorry then throwAbortTerm
219
+ -- We want `#eval` to work even in the core library, so if `ofFormat` isn't available,
220
+ -- we fall back on a `Format`-based approach.
221
+ if (← getEnv).contains ``Lean.MessageData.ofFormat then
222
+ mkAct id (mkMessageData Β·) e
223
+ else
224
+ mkAct Lean.MessageData.ofFormat (mkFormat Β·) e
225
+ let res ← act.eval
226
+ return Sum.inr (res, act.printVal)
227
+ catch ex =>
228
+ return Sum.inl ex
229
+ if !output.isEmpty then logInfoAt tk output
230
+ match exOrRes with
231
+ | .inl ex => logException ex
232
+ | .inr (_, none) => pure ()
233
+ | .inr (res, some type) =>
234
+ if eval.type.get (← getOptions) then
235
+ logInfo m!"{res} : {type}"
236
+ else
237
+ logInfo res
238
+
239
+ @[implemented_by elabEvalCoreUnsafe]
240
+ opaque elabEvalCore (bang : Bool) (tk term : Syntax) (expectedType? : Option Expr) : CommandElabM Unit
241
+
242
+ @[builtin_command_elab Β«evalΒ»]
243
+ def elabEval : CommandElab
244
+ | `(#eval%$tk $term) => elabEvalCore false tk term none
245
+ | _ => throwUnsupportedSyntax
246
+
247
+ @[builtin_command_elab evalBang]
248
+ def elabEvalBang : CommandElab
249
+ | `(#eval!%$tk $term) => elabEvalCore true tk term none
250
+ | _ => throwUnsupportedSyntax
251
+
252
+ @[builtin_command_elab runCmd]
253
+ def elabRunCmd : CommandElab
254
+ | `(run_cmd%$tk $elems:doSeq) => do
255
+ unless (← getEnv).contains ``CommandElabM do
256
+ throwError "to use this command, include `import Lean.Elab.Command`"
257
+ elabEvalCore false tk (← `(discard do $elems)) (mkApp (mkConst ``CommandElabM) (mkConst ``Unit))
258
+ | _ => throwUnsupportedSyntax
259
+
260
+ @[builtin_command_elab runElab]
261
+ def elabRunElab : CommandElab
262
+ | `(run_elab%$tk $elems:doSeq) => do
263
+ unless (← getEnv).contains ``TermElabM do
264
+ throwError "to use this command, include `import Lean.Elab.Term`"
265
+ elabEvalCore false tk (← `(discard do $elems)) (mkApp (mkConst ``TermElabM) (mkConst ``Unit))
266
+ | _ => throwUnsupportedSyntax
267
+
268
+ @[builtin_command_elab runMeta]
269
+ def elabRunMeta : CommandElab := fun stx =>
270
+ match stx with
271
+ | `(run_meta%$tk $elems:doSeq) => do
272
+ unless (← getEnv).contains ``MetaM do
273
+ throwError "to use this command, include `import Lean.Meta.Basic`"
274
+ elabEvalCore false tk (← `(discard do $elems)) (mkApp (mkConst ``MetaM) (mkConst ``Unit))
275
+ | _ => throwUnsupportedSyntax
276
+
277
+ end Lean.Elab.Command
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/BuiltinNotation.lean ADDED
@@ -0,0 +1,534 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2019 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Gabriel Ebner
5
+ -/
6
+ prelude
7
+ import Lean.Compiler.BorrowedAnnotation
8
+ import Lean.Meta.KAbstract
9
+ import Lean.Meta.Closure
10
+ import Lean.Meta.MatchUtil
11
+ import Lean.Compiler.ImplementedByAttr
12
+ import Lean.Elab.SyntheticMVars
13
+ import Lean.Elab.Eval
14
+ import Lean.Elab.Binders
15
+
16
+ namespace Lean.Elab.Term
17
+ open Meta
18
+
19
+ @[builtin_term_elab coeNotation] def elabCoe : TermElab := fun stx expectedType? => do
20
+ let stx := stx[1]
21
+ tryPostponeIfNoneOrMVar expectedType?
22
+ let e ← elabTerm stx none
23
+ if expectedType?.isNone then
24
+ throwError "invalid coercion notation, expected type is not known"
25
+ ensureHasType expectedType? e
26
+
27
+ @[builtin_term_elab coeFunNotation] def elabCoeFunNotation : TermElab := fun stx _ => do
28
+ let x ← elabTerm stx[1] none
29
+ if let some ty ← coerceToFunction? x then
30
+ return ty
31
+ else
32
+ throwError "cannot coerce to function{indentExpr x}"
33
+
34
+ @[builtin_term_elab coeSortNotation] def elabCoeSortNotation : TermElab := fun stx _ => do
35
+ let x ← elabTerm stx[1] none
36
+ if let some ty ← coerceToSort? x then
37
+ return ty
38
+ else
39
+ throwError "cannot coerce to sort{indentExpr x}"
40
+
41
+ @[builtin_term_elab anonymousCtor] def elabAnonymousCtor : TermElab := fun stx expectedType? =>
42
+ match stx with
43
+ | `(⟨$args,*⟩) => do
44
+ tryPostponeIfNoneOrMVar expectedType?
45
+ match expectedType? with
46
+ | some expectedType =>
47
+ let expectedType ← whnf expectedType
48
+ matchConstInduct expectedType.getAppFn
49
+ (fun _ => throwError "invalid constructor ⟨...⟩, expected type must be an inductive type {indentExpr expectedType}")
50
+ (fun ival _ => do
51
+ match ival.ctors with
52
+ | [ctor] =>
53
+ if isPrivateNameFromImportedModule (← getEnv) ctor then
54
+ throwError "invalid ⟨...⟩ notation, constructor for `{ival.name}` is marked as private"
55
+ let cinfo ← getConstInfoCtor ctor
56
+ let numExplicitFields ← forallTelescopeReducing cinfo.type fun xs _ => do
57
+ let mut n := 0
58
+ for h : i in [cinfo.numParams:xs.size] do
59
+ if (← getFVarLocalDecl xs[i]).binderInfo.isExplicit then
60
+ n := n + 1
61
+ return n
62
+ let args := args.getElems
63
+ if args.size < numExplicitFields then
64
+ throwError "invalid constructor ⟨...⟩, insufficient number of arguments, constructs '{ctor}' has #{numExplicitFields} explicit fields, but only #{args.size} provided"
65
+ let newStx ← if args.size == numExplicitFields then
66
+ `($(mkCIdentFrom stx ctor (canonical := true)) $(args)*)
67
+ else if numExplicitFields == 0 then
68
+ throwError "invalid constructor ⟨...⟩, insufficient number of arguments, constructs '{ctor}' does not have explicit fields, but #{args.size} provided"
69
+ else
70
+ let extra := args[(numExplicitFields-1)...args.size]
71
+ let newLast ← `(⟨$[$extra],*⟩)
72
+ let newArgs := args[*...(numExplicitFields-1)].toArray.push newLast
73
+ `($(mkCIdentFrom stx ctor (canonical := true)) $(newArgs)*)
74
+ withMacroExpansion stx newStx $ elabTerm newStx expectedType?
75
+ | _ => throwError "invalid constructor ⟨...⟩, expected type must be an inductive type with only one constructor {indentExpr expectedType}")
76
+ | none => throwError "invalid constructor ⟨...⟩, expected type must be known"
77
+ | _ => throwUnsupportedSyntax
78
+
79
+ @[builtin_term_elab borrowed] def elabBorrowed : TermElab := fun stx expectedType? =>
80
+ match stx with
81
+ | `(@& $e) => return markBorrowed (← elabTerm e expectedType?)
82
+ | _ => throwUnsupportedSyntax
83
+
84
+ @[builtin_macro Lean.Parser.Term.show] def expandShow : Macro := fun stx =>
85
+ match stx with
86
+ | `(show $type by%$b $tac) => `(show $type from by%$b $tac)
87
+ | _ => Macro.throwUnsupported
88
+
89
+ @[builtin_term_elab Lean.Parser.Term.show] def elabShow : TermElab := fun stx expectedType? => do
90
+ match stx with
91
+ | `(show $type from $val) =>
92
+ /-
93
+ We first elaborate the type and try to unify it with the expected type if available.
94
+ Note that, we should not throw an error if the types do not unify. Recall that we have coercions and
95
+ the following is supported in Lean 3 and 4.
96
+ ```
97
+ example : Int :=
98
+ show Nat from 0
99
+ ```
100
+ -/
101
+ let type ← withSynthesize (postpone := .yes) do
102
+ let type ← elabType type
103
+ if let some expectedType := expectedType? then
104
+ -- Recall that a similar approach is used when elaborating applications
105
+ discard <| isDefEq expectedType type
106
+ return type
107
+ /-
108
+ Recall that we do not use the same approach used to elaborate type ascriptions.
109
+ For the `($val : $type)` notation, we just elaborate `val` using `type` and
110
+ ensure it has type `type`. This approach only ensure the type resulting expression
111
+ is definitionally equal to `type`. For the `show` notation we use `have` to ensure the type
112
+ of the resulting expression is *structurally equal* `type`. Structural equality is important,
113
+ for example, if the resulting expression is a `simp`/`rw` parameter. Here is an example:
114
+ ```
115
+ example (x : Nat) : (x + 0) + y = x + y := by
116
+ rw [show x + 0 = x from rfl]
117
+ ```
118
+ -/
119
+ let thisId := mkIdentFrom stx `this
120
+ let valNew ← `(have $thisId:ident : $(← exprToSyntax type) := $val; $thisId)
121
+ elabTerm valNew expectedType?
122
+ | _ => throwUnsupportedSyntax
123
+
124
+ @[builtin_macro Lean.Parser.Term.suffices] def expandSuffices : Macro
125
+ | `(suffices%$tk $x:ident : $type from $val; $body) => `(have%$tk $x:ident : $type := $body; $val)
126
+ | `(suffices%$tk _%$x : $type from $val; $body) => `(have%$tk _%$x : $type := $body; $val)
127
+ | `(suffices%$tk $hy:hygieneInfo $type from $val; $body) => `(have%$tk $hy:hygieneInfo : $type := $body; $val)
128
+ | `(suffices%$tk $x:ident : $type $b:byTactic'; $body) =>
129
+ -- Pass on `SourceInfo` of `b` to `have`. This is necessary to display the goal state in the
130
+ -- trailing whitespace of `by` and sound since `byTactic` and `byTactic'` are identical.
131
+ let b := ⟨b.raw.setKind `Lean.Parser.Term.byTactic⟩
132
+ `(have%$tk $x:ident : $type := $body; $b:byTactic)
133
+ | `(suffices%$tk _%$x : $type $b:byTactic'; $body) =>
134
+ let b := ⟨b.raw.setKind `Lean.Parser.Term.byTactic⟩
135
+ `(have%$tk _%$x : $type := $body; $b:byTactic)
136
+ | `(suffices%$tk $hy:hygieneInfo $type $b:byTactic'; $body) =>
137
+ let b := ⟨b.raw.setKind `Lean.Parser.Term.byTactic⟩
138
+ `(have%$tk $hy:hygieneInfo : $type := $body; $b:byTactic)
139
+ | _ => Macro.throwUnsupported
140
+
141
+ open Lean.Parser in
142
+ private def elabParserMacroAux (prec e : Term) (withAnonymousAntiquot : Bool) : TermElabM Syntax := do
143
+ let (some declName) ← getDeclName?
144
+ | throwError "invalid `leading_parser` macro, it must be used in definitions"
145
+ match extractMacroScopes declName with
146
+ | { name := .str _ s, .. } =>
147
+ let kind := quote declName
148
+ let mut p ← ``(withAntiquot
149
+ (mkAntiquot $(quote s) $kind $(quote withAnonymousAntiquot))
150
+ (leadingNode $kind $prec $e))
151
+ -- cache only unparameterized parsers
152
+ if (← getLCtx).all (Β·.isAuxDecl) then
153
+ p ← ``(withCache $kind $p)
154
+ return p
155
+ | _ => throwError "invalid `leading_parser` macro, unexpected declaration name"
156
+
157
+ @[builtin_term_elab Β«leading_parserΒ»] def elabLeadingParserMacro : TermElab :=
158
+ adaptExpander fun
159
+ | `(leading_parser $[: $prec?]? $[(withAnonymousAntiquot := $anon?)]? $e) =>
160
+ elabParserMacroAux (prec?.getD (quote Parser.maxPrec)) e (anon?.all (Β·.raw.isOfKind ``Parser.Term.trueVal))
161
+ | _ => throwUnsupportedSyntax
162
+
163
+ private def elabTParserMacroAux (prec lhsPrec e : Term) : TermElabM Syntax := do
164
+ let declName? ← getDeclName?
165
+ match declName? with
166
+ | some declName => let kind := quote declName; ``(Lean.Parser.trailingNode $kind $prec $lhsPrec $e)
167
+ | none => throwError "invalid `trailing_parser` macro, it must be used in definitions"
168
+
169
+ @[builtin_term_elab Β«trailing_parserΒ»] def elabTrailingParserMacro : TermElab :=
170
+ adaptExpander fun stx => match stx with
171
+ | `(trailing_parser$[:$prec?]?$[:$lhsPrec?]? $e) =>
172
+ elabTParserMacroAux (prec?.getD <| quote Parser.maxPrec) (lhsPrec?.getD <| quote 0) e
173
+ | _ => throwUnsupportedSyntax
174
+
175
+ @[builtin_term_elab Lean.Parser.Term.panic] def elabPanic : TermElab := fun stx expectedType? => do
176
+ match stx with
177
+ | `(panic! $arg) =>
178
+ let pos ← getRefPosition
179
+ let env ← getEnv
180
+ let stxNew ← match (← getDeclName?) with
181
+ | some declName => `(panicWithPosWithDecl $(quote (toString env.mainModule)) $(quote (toString declName)) $(quote pos.line) $(quote pos.column) $arg)
182
+ | none => `(panicWithPos $(quote (toString env.mainModule)) $(quote pos.line) $(quote pos.column) $arg)
183
+ withMacroExpansion stx stxNew $ elabTerm stxNew expectedType?
184
+ | _ => throwUnsupportedSyntax
185
+
186
+ @[builtin_macro Lean.Parser.Term.unreachable] def expandUnreachable : Macro := fun _ =>
187
+ `(panic! "unreachable code has been reached")
188
+
189
+ @[builtin_macro Lean.Parser.Term.assert] def expandAssert : Macro
190
+ | `(assert! $cond; $body) =>
191
+ match cond.raw.reprint with
192
+ | some code => `(if $cond then $body else panic! ("assertion violation: " ++ $(quote code)))
193
+ | none => `(if $cond then $body else panic! ("assertion violation"))
194
+ | _ => Macro.throwUnsupported
195
+
196
+ register_builtin_option debugAssertions : Bool := {
197
+ defValue := false
198
+ descr := "enable `debug_assert!` statements\
199
+ \n\
200
+ \nDefaults to `false` unless the Lake `buildType` is `debug`."
201
+ }
202
+
203
+ @[builtin_term_elab Lean.Parser.Term.debugAssert] def elabDebugAssert : TermElab :=
204
+ adaptExpander fun
205
+ | `(Parser.Term.debugAssert| debug_assert! $cond; $body) => do
206
+ if debugAssertions.get (← getOptions) then
207
+ `(assert! $cond; $body)
208
+ else
209
+ return body
210
+ | _ => throwUnsupportedSyntax
211
+
212
+ @[builtin_macro Lean.Parser.Term.dbgTrace] def expandDbgTrace : Macro
213
+ | `(dbg_trace $arg:interpolatedStr; $body) => `(dbgTrace (s! $arg) fun _ => $body)
214
+ | `(dbg_trace $arg:term; $body) => `(dbgTrace (toString $arg) fun _ => $body)
215
+ | _ => Macro.throwUnsupported
216
+
217
+ @[builtin_term_elab Β«sorryΒ»] def elabSorry : TermElab := fun _ expectedType? => do
218
+ let type ← expectedType?.getDM mkFreshTypeMVar
219
+ mkLabeledSorry type (synthetic := false) (unique := true)
220
+
221
+ /-- Return syntax `Prod.mk elems[0] (Prod.mk elems[1] ... (Prod.mk elems[elems.size - 2] elems[elems.size - 1])))` -/
222
+ partial def mkPairs (elems : Array Term) : MacroM Term :=
223
+ let rec loop (i : Nat) (acc : Term) := do
224
+ if i > 0 then
225
+ let i := i - 1
226
+ let elem := elems[i]!
227
+ let acc ← `(Prod.mk $elem $acc)
228
+ loop i acc
229
+ else
230
+ pure acc
231
+ loop (elems.size - 1) elems.back!
232
+
233
+ /-- Return syntax `PProd.mk elems[0] (PProd.mk elems[1] ... (PProd.mk elems[elems.size - 2] elems[elems.size - 1])))` -/
234
+ partial def mkPPairs (elems : Array Term) : MacroM Term :=
235
+ let rec loop (i : Nat) (acc : Term) := do
236
+ if i > 0 then
237
+ let i := i - 1
238
+ let elem := elems[i]!
239
+ let acc ← `(PProd.mk $elem $acc)
240
+ loop i acc
241
+ else
242
+ pure acc
243
+ loop (elems.size - 1) elems.back!
244
+
245
+ /-- Return syntax `MProd.mk elems[0] (MProd.mk elems[1] ... (MProd.mk elems[elems.size - 2] elems[elems.size - 1])))` -/
246
+ partial def mkMPairs (elems : Array Term) : MacroM Term :=
247
+ let rec loop (i : Nat) (acc : Term) := do
248
+ if i > 0 then
249
+ let i := i - 1
250
+ let elem := elems[i]!
251
+ let acc ← `(MProd.mk $elem $acc)
252
+ loop i acc
253
+ else
254
+ pure acc
255
+ loop (elems.size - 1) elems.back!
256
+
257
+
258
+ open Parser in
259
+ partial def hasCDot : Syntax β†’ Bool
260
+ | Syntax.node _ k args =>
261
+ if k == ``Term.paren || k == ``Term.typeAscription || k == ``Term.tuple then false
262
+ else if k == ``Term.cdot then true
263
+ else args.any hasCDot
264
+ | _ => false
265
+
266
+ /--
267
+ Return `some` if succeeded expanding `Β·` notation occurring in
268
+ the given syntax. Otherwise, return `none`.
269
+ Examples:
270
+ - `Β· + 1` => `fun x => x + 1`
271
+ - `f Β· Β· b` => `fun x1 x2 => f x1 x2 b` -/
272
+ partial def expandCDot? (stx : Term) : MacroM (Option Term) := do
273
+ if hasCDot stx then
274
+ withFreshMacroScope do
275
+ let mut (newStx, binders) ← (go stx).run #[]
276
+ if binders.size == 1 then
277
+ -- It is nicer using `x` over `x1` if there's only a single binder.
278
+ let x1 := binders[0]!
279
+ let x := mkIdentFrom x1 (← MonadQuotation.addMacroScope `x) (canonical := true)
280
+ binders := binders.set! 0 x
281
+ newStx ← newStx.replaceM fun s => pure (if s == x1 then x else none)
282
+ `(fun $binders* => $(⟨newStx⟩))
283
+ else
284
+ pure none
285
+ where
286
+ /--
287
+ Auxiliary function for expanding the `Β·` notation.
288
+ The extra state `Array Syntax` contains the new binder names.
289
+ If `stx` is a `Β·`, we create a fresh identifier, store it in the
290
+ extra state, and return it. Otherwise, we just return `stx`.
291
+ -/
292
+ go : Syntax β†’ StateT (Array Ident) MacroM Syntax
293
+ | stx@`(($(_))) => pure stx
294
+ | stx@`(Β·) => do
295
+ let name ← MonadQuotation.addMacroScope <| Name.mkSimple s!"x{(← get).size + 1}"
296
+ let id := mkIdentFrom stx name (canonical := true)
297
+ modify (fun s => s.push id)
298
+ pure id
299
+ | stx => match stx with
300
+ | .node _ k args => do
301
+ let args ←
302
+ if k == choiceKind then
303
+ if args.isEmpty then
304
+ return stx
305
+ let s ← get
306
+ let args' ← args.mapM (fun arg => go arg |>.run s)
307
+ let s' := args'[0]!.2
308
+ unless args'.all (fun (_, s'') => s''.size == s'.size) do
309
+ Macro.throwErrorAt stx "Ambiguous notation in cdot function has different numbers of 'Β·' arguments in each alternative."
310
+ set s'
311
+ pure <| args'.map Prod.fst
312
+ else
313
+ args.mapM go
314
+ return .node (.fromRef stx (canonical := true)) k args
315
+ | _ => pure stx
316
+
317
+ /--
318
+ Helper method for elaborating terms such as `(.+.)` where a constant name is expected.
319
+ This method is usually used to implement tactics that take function names as arguments
320
+ (e.g., `simp`).
321
+ -/
322
+ def elabCDotFunctionAlias? (stx : Term) : TermElabM (Option Expr) := do
323
+ let some stx ← liftMacroM <| expandCDotArg? stx | pure none
324
+ let stx ← liftMacroM <| expandMacros stx
325
+ match stx with
326
+ | `(fun $binders* => $f $args*) =>
327
+ if binders.raw.toList.isPerm args.raw.toList then
328
+ try Term.resolveId? f catch _ => return none
329
+ else
330
+ return none
331
+ | `(fun $binders* => binop% $f $a $b)
332
+ | `(fun $binders* => binop_lazy% $f $a $b)
333
+ | `(fun $binders* => leftact% $f $a $b)
334
+ | `(fun $binders* => rightact% $f $a $b)
335
+ | `(fun $binders* => binrel% $f $a $b)
336
+ | `(fun $binders* => binrel_no_prop% $f $a $b) =>
337
+ if binders == #[a, b] || binders == #[b, a] then
338
+ try Term.resolveId? f catch _ => return none
339
+ else
340
+ return none
341
+ | `(fun $binders* => unop% $f $a) =>
342
+ if binders == #[a] then
343
+ try Term.resolveId? f catch _ => return none
344
+ else
345
+ return none
346
+ | _ => return none
347
+ where
348
+ expandCDotArg? (stx : Term) : MacroM (Option Term) :=
349
+ match stx with
350
+ | `(($e)) => Term.expandCDot? e
351
+ | _ => Term.expandCDot? stx
352
+
353
+ @[builtin_macro Lean.Parser.Term.paren] def expandParen : Macro
354
+ | `(($e)) => return (← expandCDot? e).getD e
355
+ | _ => Macro.throwUnsupported
356
+
357
+ @[builtin_macro Lean.Parser.Term.tuple] def expandTuple : Macro
358
+ | `(()) => ``(Unit.unit)
359
+ | `(($e, $es,*)) => do
360
+ let pairs ← mkPairs (#[e] ++ es)
361
+ return (← expandCDot? pairs).getD pairs
362
+ | _ => Macro.throwUnsupported
363
+
364
+ @[builtin_macro Lean.Parser.Term.typeAscription] def expandTypeAscription : Macro
365
+ | `(($e : $(type)?)) => do
366
+ match (← expandCDot? e) with
367
+ | some e => `(($e : $(type)?))
368
+ | none => Macro.throwUnsupported
369
+ | _ => Macro.throwUnsupported
370
+
371
+ @[builtin_term_elab typeAscription] def elabTypeAscription : TermElab
372
+ | `(($e : $type)), _ => do
373
+ let type ← withSynthesize (postpone := .yes) <| elabType type
374
+ let e ← elabTerm e type
375
+ ensureHasType type e
376
+ | `(($e :)), expectedType? => do
377
+ let e ← withSynthesize (postpone := .no) <| elabTerm e none
378
+ ensureHasType expectedType? e
379
+ | _, _ => throwUnsupportedSyntax
380
+
381
+ /-- Return `true` if `lhs` is a free variable and `rhs` does not depend on it. -/
382
+ private def isSubstCandidate (lhs rhs : Expr) : MetaM Bool :=
383
+ if lhs.isFVar then
384
+ return !(← dependsOn rhs lhs.fvarId!)
385
+ else
386
+ return false
387
+
388
+ /--
389
+ Given an expression `e` that is the elaboration of `stx`, if `e` is a free variable, then return `k stx`.
390
+ Otherwise, return `(fun x => k x) e`
391
+ -/
392
+ private def withLocalIdentFor (stx : Term) (e : Expr) (k : Term β†’ TermElabM Expr) : TermElabM Expr := do
393
+ if e.isFVar then
394
+ k stx
395
+ else
396
+ let id ← mkFreshUserName `h
397
+ let aux ← withLocalDeclD id (← inferType e) fun x => do mkLambdaFVars #[x] (← k (mkIdentFrom stx id))
398
+ return mkApp aux e
399
+
400
+ @[builtin_term_elab subst] def elabSubst : TermElab := fun stx expectedType? => do
401
+ let expectedType? ← tryPostponeIfHasMVars? expectedType?
402
+ match stx with
403
+ | `($heqStx β–Έ $hStx) => do
404
+ synthesizeSyntheticMVars
405
+ let mut heq ← withSynthesize <| elabTerm heqStx none
406
+ let heqType ← inferType heq
407
+ let heqType ← instantiateMVars heqType
408
+ match (← Meta.matchEq? heqType) with
409
+ | none => throwError "invalid `β–Έ` notation, argument{indentExpr heq}\nhas type{indentExpr heqType}\nequality expected"
410
+ | some (Ξ±, lhs, rhs) =>
411
+ let mut lhs := lhs
412
+ let mut rhs := rhs
413
+ let mkMotive (lhs typeWithLooseBVar : Expr) := do
414
+ withLocalDeclD (← mkFreshUserName `x) Ξ± fun x => do
415
+ withLocalDeclD (← mkFreshUserName `h) (← mkEq lhs x) fun h => do
416
+ mkLambdaFVars #[x, h] $ typeWithLooseBVar.instantiate1 x
417
+ match expectedType? with
418
+ | some expectedType =>
419
+ let mut expectedAbst ← kabstract expectedType rhs
420
+ unless expectedAbst.hasLooseBVars do
421
+ expectedAbst ← kabstract expectedType lhs
422
+ unless expectedAbst.hasLooseBVars do
423
+ throwError "invalid `β–Έ` notation, expected result type of cast is {indentExpr expectedType}\nhowever, the equality {indentExpr heq}\nof type {indentExpr heqType}\ndoes not contain the expected result type on either the left or the right hand side"
424
+ heq ← mkEqSymm heq
425
+ (lhs, rhs) := (rhs, lhs)
426
+ let hExpectedType := expectedAbst.instantiate1 lhs
427
+ let (h, badMotive?) ← withRef hStx do
428
+ let h ← elabTerm hStx hExpectedType
429
+ try
430
+ return (← ensureHasType hExpectedType h, none)
431
+ catch ex =>
432
+ -- if `rhs` occurs in `hType`, we try to apply `heq` to `h` too
433
+ let hType ← inferType h
434
+ let hTypeAbst ← kabstract hType rhs
435
+ unless hTypeAbst.hasLooseBVars do
436
+ throw ex
437
+ let hTypeNew := hTypeAbst.instantiate1 lhs
438
+ unless (← isDefEq hExpectedType hTypeNew) do
439
+ throw ex
440
+ let motive ← mkMotive rhs hTypeAbst
441
+ if !(← isTypeCorrect motive) then
442
+ return (h, some motive)
443
+ else
444
+ return (← mkEqRec motive h (← mkEqSymm heq), none)
445
+ let motive ← mkMotive lhs expectedAbst
446
+ if badMotive?.isSome || !(← isTypeCorrect motive) then
447
+ -- Before failing try to use `subst`
448
+ if ← (isSubstCandidate lhs rhs <||> isSubstCandidate rhs lhs) then
449
+ withLocalIdentFor heqStx heq fun heqStx => do
450
+ let h ← instantiateMVars h
451
+ if h.hasMVar then
452
+ -- If `h` has metavariables, we try to elaborate `hStx` again after we substitute `heqStx`
453
+ -- Remark: re-elaborating `hStx` may be problematic if `hStx` contains the `lhs` of `heqStx` which will be eliminated by `subst`
454
+ let stxNew ← `(by subst $heqStx; exact $hStx)
455
+ withMacroExpansion stx stxNew (elabTerm stxNew expectedType)
456
+ else
457
+ withLocalIdentFor hStx h fun hStx => do
458
+ let stxNew ← `(by subst $heqStx; exact $hStx)
459
+ withMacroExpansion stx stxNew (elabTerm stxNew expectedType)
460
+ else
461
+ throwError "invalid `β–Έ` notation, failed to compute motive for the substitution"
462
+ else
463
+ mkEqRec motive h heq
464
+ | none =>
465
+ let h ← elabTerm hStx none
466
+ let hType ← inferType h
467
+ let mut hTypeAbst ← kabstract hType lhs
468
+ unless hTypeAbst.hasLooseBVars do
469
+ hTypeAbst ← kabstract hType rhs
470
+ unless hTypeAbst.hasLooseBVars do
471
+ throwError "invalid `β–Έ` notation, the equality{indentExpr heq}\nhas type {indentExpr heqType}\nbut neither side of the equality is mentioned in the type{indentExpr hType}"
472
+ heq ← mkEqSymm heq
473
+ (lhs, rhs) := (rhs, lhs)
474
+ let motive ← mkMotive lhs hTypeAbst
475
+ unless (← isTypeCorrect motive) do
476
+ throwError "invalid `β–Έ` notation, failed to compute motive for the substitution"
477
+ mkEqRec motive h heq
478
+ | _ => throwUnsupportedSyntax
479
+
480
+ @[builtin_term_elab stateRefT] def elabStateRefT : TermElab := fun stx _ => do
481
+ let Οƒ ← elabType stx[1]
482
+ let mut mStx := stx[2]
483
+ if mStx.getKind == ``Lean.Parser.Term.macroDollarArg then
484
+ mStx := mStx[1]
485
+ let m ← elabTerm mStx (← mkArrow (mkSort levelOne) (mkSort levelOne))
486
+ let Ο‰ ← mkFreshExprMVar (mkSort levelOne)
487
+ let stWorld ← mkAppM ``STWorld #[Ο‰, m]
488
+ discard <| mkInstMVar stWorld
489
+ mkAppM ``StateRefT' #[Ο‰, Οƒ, m]
490
+
491
+ @[builtin_term_elab noindex] def elabNoindex : TermElab := fun stx expectedType? => do
492
+ let e ← elabTerm stx[1] expectedType?
493
+ return DiscrTree.mkNoindexAnnotation e
494
+
495
+ @[builtin_term_elab Β«unsafeΒ»]
496
+ def elabUnsafe : TermElab := fun stx expectedType? =>
497
+ match stx with
498
+ | `(unsafe $t) => do
499
+ let t ← elabTermAndSynthesize t expectedType?
500
+ if (← logUnassignedUsingErrorInfos (← getMVars t)) then
501
+ throwAbortTerm
502
+ let t ← mkAuxDefinitionFor (← mkAuxName `unsafe) t
503
+ let .const unsafeFn unsafeLvls .. := t.getAppFn | unreachable!
504
+ let .defnInfo unsafeDefn ← getConstInfo unsafeFn | unreachable!
505
+ let implName ← mkAuxName `unsafe_impl
506
+ addDecl <| Declaration.defnDecl {
507
+ name := implName
508
+ type := unsafeDefn.type
509
+ levelParams := unsafeDefn.levelParams
510
+ value := (← mkOfNonempty unsafeDefn.type)
511
+ hints := .opaque
512
+ safety := .safe
513
+ }
514
+ setImplementedBy implName unsafeFn
515
+ return mkAppN (Lean.mkConst implName unsafeLvls) t.getAppArgs
516
+ | _ => throwUnsupportedSyntax
517
+
518
+ /-- Elaborator for `by_elab`. -/
519
+ @[builtin_term_elab byElab] def elabRunElab : TermElab := fun stx expectedType? =>
520
+ match stx with
521
+ | `(by_elab $cmds:doSeq) => do
522
+ if let `(Lean.Parser.Term.doSeq| $e:term) := cmds then
523
+ if e matches `(Lean.Parser.Term.doSeq| fun $[$_args]* => $_) then
524
+ let tac ← unsafe evalTerm
525
+ (Option Expr β†’ TermElabM Expr)
526
+ (Lean.mkForall `x .default
527
+ (mkApp (Lean.mkConst ``Option) (Lean.mkConst ``Expr))
528
+ (mkApp (Lean.mkConst ``TermElabM) (Lean.mkConst ``Expr))) e
529
+ return ← tac expectedType?
530
+ (← unsafe evalTerm (TermElabM Expr) (mkApp (Lean.mkConst ``TermElabM) (Lean.mkConst ``Expr))
531
+ (← `(do $cmds)))
532
+ | _ => throwUnsupportedSyntax
533
+
534
+ end Lean.Elab.Term
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/BuiltinTerm.lean ADDED
@@ -0,0 +1,386 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Meta.Closure
8
+ import Lean.Meta.Diagnostics
9
+ import Lean.Elab.Open
10
+ import Lean.Elab.SetOption
11
+ import Lean.Elab.Eval
12
+
13
+ namespace Lean.Elab.Term
14
+ open Meta
15
+
16
+ @[builtin_term_elab Β«propΒ»] def elabProp : TermElab := fun _ _ =>
17
+ return mkSort levelZero
18
+
19
+ private def elabOptLevel (stx : Syntax) : TermElabM Level :=
20
+ if stx.isNone then
21
+ pure levelZero
22
+ else
23
+ elabLevel stx[0]
24
+
25
+ @[builtin_term_elab Β«sortΒ»] def elabSort : TermElab := fun stx _ =>
26
+ return mkSort (← elabOptLevel stx[1])
27
+
28
+ @[builtin_term_elab Β«typeΒ»] def elabTypeStx : TermElab := fun stx _ =>
29
+ return mkSort (mkLevelSucc (← elabOptLevel stx[1]))
30
+
31
+ /-!
32
+ the method `resolveName` adds a completion point for it using the given
33
+ expected type. Thus, we propagate the expected type if `stx[0]` is an identifier.
34
+ It doesn't "hurt" if the identifier can be resolved because the expected type is not used in this case.
35
+ Recall that if the name resolution fails a synthetic sorry is returned.-/
36
+
37
+ @[builtin_term_elab Β«pipeCompletionΒ»] def elabPipeCompletion : TermElab := fun stx expectedType? => do
38
+ let e ← elabTerm stx[0] none
39
+ unless e.isSorry do
40
+ addDotCompletionInfo stx e expectedType?
41
+ throwErrorAt stx[1] "invalid field notation, identifier or numeral expected"
42
+
43
+ @[builtin_term_elab Β«completionΒ»] def elabCompletion : TermElab := fun stx expectedType? => do
44
+ /- `ident.` is ambiguous in Lean, we may try to be completing a declaration name or access a "field". -/
45
+ if stx[0].isIdent then
46
+ -- Add both an `id` and a `dot` `CompletionInfo` and have the language server figure out which
47
+ -- one to use.
48
+ addCompletionInfo <| CompletionInfo.id stx stx[0].getId (danglingDot := true) (← getLCtx) expectedType?
49
+ let s ← saveState
50
+ try
51
+ let e ← elabTerm stx[0] none
52
+ addDotCompletionInfo stx e expectedType?
53
+ catch _ =>
54
+ s.restore
55
+ throwErrorAt stx[1] "invalid field notation, identifier or numeral expected"
56
+ else
57
+ elabPipeCompletion stx expectedType?
58
+
59
+ @[builtin_term_elab Β«holeΒ»] def elabHole : TermElab := fun stx expectedType? => do
60
+ let kind := if (← read).inPattern || !(← read).holesAsSyntheticOpaque then MetavarKind.natural else MetavarKind.syntheticOpaque
61
+ let mvar ← mkFreshExprMVar expectedType? kind
62
+ registerMVarErrorHoleInfo mvar.mvarId! stx
63
+ pure mvar
64
+
65
+ @[builtin_term_elab Β«syntheticHoleΒ»] def elabSyntheticHole : TermElab := fun stx expectedType? => do
66
+ let arg := stx[1]
67
+ let userName := if arg.isIdent then arg.getId else Name.anonymous
68
+ let mkNewHole : Unit β†’ TermElabM Expr := fun _ => do
69
+ let kind := if (← read).inPattern then MetavarKind.natural else MetavarKind.syntheticOpaque
70
+ let mvar ← mkFreshExprMVar expectedType? kind userName
71
+ registerMVarErrorHoleInfo mvar.mvarId! stx
72
+ return mvar
73
+ if userName.isAnonymous || (← read).inPattern then
74
+ mkNewHole ()
75
+ else
76
+ match (← getMCtx).findUserName? userName with
77
+ | none => mkNewHole ()
78
+ | some mvarId =>
79
+ let mvar := mkMVar mvarId
80
+ let mvarDecl ← getMVarDecl mvarId
81
+ let lctx ← getLCtx
82
+ if mvarDecl.lctx.isSubPrefixOf lctx then
83
+ return mvar
84
+ else match (← getExprMVarAssignment? mvarId) with
85
+ | some val =>
86
+ let val ← instantiateMVars val
87
+ if (← MetavarContext.isWellFormed lctx val) then
88
+ return val
89
+ else
90
+ withLCtx mvarDecl.lctx mvarDecl.localInstances do
91
+ throwError "synthetic hole has already been defined and assigned to value incompatible with the current context{indentExpr val}"
92
+ | none =>
93
+ if (← mvarId.isDelayedAssigned) then
94
+ -- We can try to improve this case if needed.
95
+ throwError "synthetic hole has already beend defined and delayed assigned with an incompatible local context"
96
+ else if lctx.isSubPrefixOf mvarDecl.lctx then
97
+ let mvarNew ← mkNewHole ()
98
+ mvarId.assign mvarNew
99
+ return mvarNew
100
+ else
101
+ throwError "synthetic hole has already been defined with an incompatible local context"
102
+
103
+ @[builtin_term_elab Lean.Parser.Term.omission] def elabOmission : TermElab := fun stx expectedType? => do
104
+ logWarning m!"\
105
+ The 'β‹―' token is used by the pretty printer to indicate omitted terms, and it should not be used directly. \
106
+ It logs this warning and then elaborates like '_'.\
107
+ \n\n\
108
+ The presence of 'β‹―' in pretty printing output is controlled by the 'pp.maxSteps', 'pp.deepTerms' and 'pp.proofs' options. \
109
+ These options can be further adjusted using 'pp.deepTerms.threshold' and 'pp.proofs.threshold'. \
110
+ If this 'β‹―' was copied from the Infoview, the hover there for the original 'β‹―' explains which of these options led to the omission."
111
+ elabHole stx expectedType?
112
+
113
+ @[builtin_term_elab Β«letMVarΒ»] def elabLetMVar : TermElab := fun stx expectedType? => do
114
+ match stx with
115
+ | `(let_mvar% ? $n := $e; $b) =>
116
+ match (← getMCtx).findUserName? n.getId with
117
+ | some _ => throwError "invalid 'let_mvar%', metavariable '?{n.getId}' has already been used"
118
+ | none =>
119
+ let e ← elabTerm e none
120
+ let mvar ← mkFreshExprMVar (← inferType e) MetavarKind.syntheticOpaque n.getId
121
+ mvar.mvarId!.assign e
122
+ -- We use `mkSaveInfoAnnotation` to make sure the info trees for `e` are saved even if `b` is a metavariable.
123
+ return mkSaveInfoAnnotation (← elabTerm b expectedType?)
124
+ | _ => throwUnsupportedSyntax
125
+
126
+ private def getMVarFromUserName (ident : Syntax) : MetaM Expr := do
127
+ match (← getMCtx).findUserName? ident.getId with
128
+ | none => throwError "unknown metavariable '?{ident.getId}'"
129
+ | some mvarId => instantiateMVars (mkMVar mvarId)
130
+
131
+
132
+ @[builtin_term_elab Β«waitIfTypeMVarΒ»] def elabWaitIfTypeMVar : TermElab := fun stx expectedType? => do
133
+ match stx with
134
+ | `(wait_if_type_mvar% ? $n; $b) =>
135
+ tryPostponeIfMVar (← inferType (← getMVarFromUserName n))
136
+ elabTerm b expectedType?
137
+ | _ => throwUnsupportedSyntax
138
+
139
+ @[builtin_term_elab Β«waitIfTypeContainsMVarΒ»] def elabWaitIfTypeContainsMVar : TermElab := fun stx expectedType? => do
140
+ match stx with
141
+ | `(wait_if_type_contains_mvar% ? $n; $b) =>
142
+ if (← instantiateMVars (← inferType (← getMVarFromUserName n))).hasExprMVar then
143
+ tryPostpone
144
+ elabTerm b expectedType?
145
+ | _ => throwUnsupportedSyntax
146
+
147
+ @[builtin_term_elab Β«waitIfContainsMVarΒ»] def elabWaitIfContainsMVar : TermElab := fun stx expectedType? => do
148
+ match stx with
149
+ | `(wait_if_contains_mvar% ? $n; $b) =>
150
+ if (← getMVarFromUserName n).hasExprMVar then
151
+ tryPostpone
152
+ elabTerm b expectedType?
153
+ | _ => throwUnsupportedSyntax
154
+
155
+ @[builtin_term_elab byTactic] def elabByTactic : TermElab := fun stx expectedType? => do
156
+ match expectedType? with
157
+ | some expectedType =>
158
+ -- `by` switches from an exported to a private context, so we must disallow unassigned
159
+ -- metavariables in the goal in this case as they could otherwise leak private data back into
160
+ -- the exported context.
161
+ mkTacticMVar expectedType stx .term (delayOnMVars := (← getEnv).isExporting)
162
+ | none =>
163
+ tryPostpone
164
+ throwError ("invalid 'by' tactic, expected type has not been provided")
165
+
166
+ @[builtin_term_elab noImplicitLambda] def elabNoImplicitLambda : TermElab := fun stx expectedType? =>
167
+ elabTerm stx[1] (mkNoImplicitLambdaAnnotation <$> expectedType?)
168
+
169
+ @[builtin_term_elab Lean.Parser.Term.cdot] def elabBadCDot : TermElab := fun stx expectedType? => do
170
+ if stx[0].getAtomVal == "." then
171
+ -- Users may input bad cdots because they are trying to auto-complete them using the expected type
172
+ addCompletionInfo <| CompletionInfo.dotId stx .anonymous (← getLCtx) expectedType?
173
+ throwError "invalid occurrence of `Β·` notation, it must be surrounded by parentheses (e.g. `(Β· + 1)`)"
174
+
175
+ @[builtin_term_elab str] def elabStrLit : TermElab := fun stx _ => do
176
+ match stx.isStrLit? with
177
+ | some val => pure $ mkStrLit val
178
+ | none => throwIllFormedSyntax
179
+
180
+ private def mkFreshTypeMVarFor (expectedType? : Option Expr) : TermElabM Expr := do
181
+ let typeMVar ← mkFreshTypeMVar MetavarKind.synthetic
182
+ match expectedType? with
183
+ | some expectedType => discard <| isDefEq expectedType typeMVar
184
+ | _ => pure ()
185
+ return typeMVar
186
+
187
+ @[builtin_term_elab num] def elabNumLit : TermElab := fun stx expectedType? => do
188
+ let val ← match stx.isNatLit? with
189
+ | some val => pure val
190
+ | none => throwIllFormedSyntax
191
+ let typeMVar ← mkFreshTypeMVarFor expectedType?
192
+ let u ← try
193
+ getDecLevel typeMVar
194
+ catch ex =>
195
+ match expectedType? with
196
+ | some expectedType =>
197
+ if (← isProp expectedType) then
198
+ throwError m!"numerals are data in Lean, but the expected type is a proposition{indentExpr expectedType} : Prop"
199
+ else
200
+ throwError m!"numerals are data in Lean, but the expected type is universe polymorphic and may be a proposition{indentExpr expectedType} : {← inferType expectedType}"
201
+ | none => throw ex
202
+ let extraMsg := m!"numerals are polymorphic in Lean, but the numeral `{val}` cannot be used in a context where the expected type is{indentExpr typeMVar}\ndue to the absence of the instance above"
203
+ let mvar ← mkInstMVar (mkApp2 (Lean.mkConst ``OfNat [u]) typeMVar (mkRawNatLit val)) extraMsg
204
+ let r := mkApp3 (Lean.mkConst ``OfNat.ofNat [u]) typeMVar (mkRawNatLit val) mvar
205
+ registerMVarErrorImplicitArgInfo mvar.mvarId! stx r
206
+ return r
207
+
208
+ @[builtin_term_elab rawNatLit] def elabRawNatLit : TermElab := fun stx _ => do
209
+ match stx[1].isNatLit? with
210
+ | some val => return mkRawNatLit val
211
+ | none => throwIllFormedSyntax
212
+
213
+ @[builtin_term_elab scientific]
214
+ def elabScientificLit : TermElab := fun stx expectedType? => do
215
+ match stx.isScientificLit? with
216
+ | none => throwIllFormedSyntax
217
+ | some (m, sign, e) =>
218
+ let typeMVar ← mkFreshTypeMVarFor expectedType?
219
+ let u ← getDecLevel typeMVar
220
+ let mvar ← mkInstMVar (mkApp (Lean.mkConst ``OfScientific [u]) typeMVar)
221
+ let r := mkApp5 (Lean.mkConst ``OfScientific.ofScientific [u]) typeMVar mvar (mkRawNatLit m) (toExpr sign) (mkRawNatLit e)
222
+ registerMVarErrorImplicitArgInfo mvar.mvarId! stx r
223
+ return r
224
+
225
+ @[builtin_term_elab char] def elabCharLit : TermElab := fun stx _ => do
226
+ match stx.isCharLit? with
227
+ | some val => return mkApp (Lean.mkConst ``Char.ofNat) (mkRawNatLit val.toNat)
228
+ | none => throwIllFormedSyntax
229
+
230
+ @[builtin_term_elab quotedName] def elabQuotedName : TermElab := fun stx _ =>
231
+ match stx[0].isNameLit? with
232
+ | some val => pure $ toExpr val
233
+ | none => throwIllFormedSyntax
234
+
235
+ @[builtin_term_elab doubleQuotedName] def elabDoubleQuotedName : TermElab := fun stx _ =>
236
+ return toExpr (← realizeGlobalConstNoOverloadWithInfo stx[2])
237
+
238
+ @[builtin_term_elab declName] def elabDeclName : TermElab := adaptExpander fun _ => do
239
+ let some declName ← getDeclName?
240
+ | throwError "invalid `decl_name%` macro, the declaration name is not available"
241
+ return (quote declName : Term)
242
+
243
+ @[builtin_term_elab Parser.Term.withDeclName] def elabWithDeclName : TermElab := fun stx expectedType? => do
244
+ let id := stx[2].getId
245
+ let id ← if stx[1].isNone then pure id else pure <| (← getCurrNamespace) ++ id
246
+ let e := stx[3]
247
+ withMacroExpansion stx e <| withDeclName id <| elabTerm e expectedType?
248
+
249
+ @[builtin_term_elab typeOf] def elabTypeOf : TermElab := fun stx _ => do
250
+ inferType (← elabTerm stx[1] none)
251
+
252
+ /--
253
+ Recall that `mkTermInfo` does not create an `ofTermInfo` node in the info tree
254
+ if `e` corresponds to a hole that is going to be filled "later" by executing a tactic or resuming elaboration.
255
+ This behavior is problematic for auxiliary elaboration steps that are "almost" no-ops.
256
+ For example, consider the elaborator for
257
+ ```
258
+ ensure_type_of% s msg e
259
+ ```
260
+ It elaborates `s`, infers its type `t`, and then elaborates `e` ensuring the resulting type is `t`.
261
+ If the elaboration of `e` is postponed, then the result is just a metavariable, and an `ofTermInfo` would not be created.
262
+ This happens because `ensure_type_of%` is almost a no-op. The elaboration of `s` does not directly contribute to the
263
+ final result, just its type.
264
+ To make sure, we don't miss any information in the `InfoTree`, we can just create a "silent" annotation to force
265
+ `mTermInfo` to create a node for the `ensure_type_of% s msg e` even if `e` has been postponed.
266
+
267
+ Another possible solution is to elaborate `ensure_type_of% s msg e` as `ensureType s e` where `ensureType` has type
268
+ ```
269
+ ensureType (s e : Ξ±) := e
270
+ ```
271
+ We decided to use the silent notation because `ensure_type_of%` is heavily used in the `Do` elaborator, and the extra
272
+ overhead could be significant.
273
+ -/
274
+ private def mkSilentAnnotationIfHole (e : Expr) : TermElabM Expr := do
275
+ if (← isTacticOrPostponedHole? e).isSome then
276
+ return mkAnnotation `_silent e
277
+ else
278
+ return e
279
+
280
+ @[builtin_term_elab ensureTypeOf] def elabEnsureTypeOf : TermElab := fun stx _ =>
281
+ match stx[2].isStrLit? with
282
+ | none => throwIllFormedSyntax
283
+ | some msg => do
284
+ let refTerm ← elabTerm stx[1] none
285
+ let refTermType ← inferType refTerm
286
+ -- See comment at `mkSilentAnnotationIfHole`
287
+ mkSilentAnnotationIfHole (← elabTermEnsuringType stx[3] refTermType (errorMsgHeader? := msg))
288
+
289
+ @[builtin_term_elab ensureExpectedType] def elabEnsureExpectedType : TermElab := fun stx expectedType? =>
290
+ match stx[1].isStrLit? with
291
+ | none => throwIllFormedSyntax
292
+ | some msg => elabTermEnsuringType stx[2] expectedType? (errorMsgHeader? := msg)
293
+
294
+ @[builtin_term_elab valueOf] def elabValueOf : TermElab := fun stx _ => do
295
+ let ident := stx[1]
296
+ let some e ← Term.resolveId? stx[1] (withInfo := true)
297
+ | throwUnknownConstantAt ident ident.getId
298
+ match e with
299
+ | .const c us => do
300
+ let cinfo ← getConstInfo c
301
+ unless cinfo.hasValue do throwErrorAt ident "Constant has no value."
302
+ return cinfo.instantiateValueLevelParams! us
303
+ | .fvar fvarId => do
304
+ let some val ← fvarId.getValue? | throwErrorAt ident "Local declaration has no value."
305
+ return val
306
+ | _ => panic! "resolveId? returned an unexpected expression"
307
+
308
+ @[builtin_term_elab clear] def elabClear : TermElab := fun stx expectedType? => do
309
+ let some (.fvar fvarId) ← isLocalIdent? stx[1]
310
+ | throwErrorAt stx[1] "not in scope"
311
+ let body := stx[3]
312
+ let canClear ← id do
313
+ if let some expectedType := expectedType? then
314
+ if ← dependsOn expectedType fvarId then
315
+ return false
316
+ for ldecl in ← getLCtx do
317
+ if ldecl.fvarId != fvarId then
318
+ if ← localDeclDependsOn ldecl fvarId then
319
+ return false
320
+ return true
321
+ if canClear then
322
+ withErasedFVars #[fvarId] do elabTerm body expectedType?
323
+ else
324
+ elabTerm body expectedType?
325
+
326
+ @[builtin_term_elab Β«openΒ»] def elabOpen : TermElab := fun stx expectedType? => do
327
+ let `(open $decl in $e) := stx | throwUnsupportedSyntax
328
+ try
329
+ pushScope
330
+ let openDecls ← elabOpenDecl decl
331
+ withTheReader Core.Context (fun ctx => { ctx with openDecls := openDecls }) do
332
+ elabTerm e expectedType?
333
+ finally
334
+ popScope
335
+
336
+ @[builtin_term_elab Β«set_optionΒ»] def elabSetOption : TermElab := fun stx expectedType? => do
337
+ let options ← Elab.elabSetOption stx[1] stx[3]
338
+ withOptions (fun _ => options) do
339
+ try
340
+ elabTerm stx[5] expectedType?
341
+ finally
342
+ if stx[1].getId == `diagnostics then
343
+ reportDiag
344
+
345
+ @[builtin_term_elab withAnnotateTerm] def elabWithAnnotateTerm : TermElab := fun stx expectedType? => do
346
+ match stx with
347
+ | `(with_annotate_term $stx $e) =>
348
+ withTermInfoContext' .anonymous stx (expectedType? := expectedType?) (elabTerm e expectedType?)
349
+ | _ => throwUnsupportedSyntax
350
+
351
+ private unsafe def evalFilePathUnsafe (stx : Syntax) : TermElabM System.FilePath :=
352
+ evalTerm System.FilePath (Lean.mkConst ``System.FilePath) stx
353
+
354
+ @[implemented_by evalFilePathUnsafe]
355
+ private opaque evalFilePath (stx : Syntax) : TermElabM System.FilePath
356
+
357
+ @[builtin_term_elab includeStr] def elabIncludeStr : TermElab
358
+ | `(include_str $path:term), _ => do
359
+ let path ← evalFilePath path
360
+ let ctx ← readThe Lean.Core.Context
361
+ let srcPath := System.FilePath.mk ctx.fileName
362
+ let some srcDir := srcPath.parent
363
+ | throwError "cannot compute parent directory of '{srcPath}'"
364
+ let path := srcDir / path
365
+ mkStrLit <$> IO.FS.readFile path
366
+ | _, _ => throwUnsupportedSyntax
367
+
368
+ @[builtin_term_elab Lean.Parser.Term.namedPattern] def elabNamedPatternErr : TermElab := fun stx _ =>
369
+ throwError "`<identifier>@<term>` is a named pattern and can only be used in pattern matching contexts{indentD stx}"
370
+
371
+ @[builtin_term_elab Β«privateDeclΒ»] def elabPrivateDecl : TermElab := fun stx expectedType? => do
372
+ match stx with
373
+ | `(Parser.Term.privateDecl| private_decl% $e) =>
374
+ if (← getEnv).isExporting then
375
+ let name ← mkAuxDeclName `_private
376
+ withoutExporting do
377
+ let e ← elabTerm e expectedType?
378
+ -- Inline as changing visibility should not affect run time.
379
+ -- Eventually we would like to be more conscious about inlining of instance fields,
380
+ -- irrespective of `private` use.
381
+ mkAuxDefinitionFor name e <* setInlineAttribute name
382
+ else
383
+ elabTerm e expectedType?
384
+ | _ => throwUnsupportedSyntax
385
+
386
+ end Lean.Elab.Term
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Calc.lean ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2022 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Elab.App
8
+
9
+ namespace Lean.Elab.Term
10
+ open Meta
11
+
12
+ /--
13
+ Decompose `e` into `(r, a, b)`.
14
+
15
+ Remark: it assumes the last two arguments are explicit.
16
+ -/
17
+ def getCalcRelation? (e : Expr) : MetaM (Option (Expr Γ— Expr Γ— Expr)) := do
18
+ if e.getAppNumArgs < 2 then
19
+ return none
20
+ else
21
+ return some (e.appFn!.appFn!, e.appFn!.appArg!, e.appArg!)
22
+
23
+ private def getRelUniv (r : Expr) : MetaM Level := do
24
+ let rType ← inferType r
25
+ forallTelescopeReducing rType fun _ sort => do
26
+ let .sort u ← whnf sort | throwError "unexpected relation type{indentExpr rType}"
27
+ return u
28
+
29
+ def mkCalcTrans (result resultType step stepType : Expr) : MetaM (Expr Γ— Expr) := do
30
+ let some (r, a, b) ← getCalcRelation? resultType | unreachable!
31
+ let some (s, _, c) ← getCalcRelation? (← instantiateMVars stepType) | unreachable!
32
+ let u ← getRelUniv r
33
+ let v ← getRelUniv s
34
+ let (Ξ±, Ξ², Ξ³) := (← inferType a, ← inferType b, ← inferType c)
35
+ let (u_1, u_2, u_3) := (← getLevel Ξ±, ← getLevel Ξ², ← getLevel Ξ³)
36
+ let w ← mkFreshLevelMVar
37
+ let t ← mkFreshExprMVar (← mkArrow Ξ± (← mkArrow Ξ³ (mkSort w)))
38
+ let selfType := mkAppN (Lean.mkConst ``Trans [u, v, w, u_1, u_2, u_3]) #[Ξ±, Ξ², Ξ³, r, s, t]
39
+ match (← trySynthInstance selfType) with
40
+ | .some self =>
41
+ let result := mkAppN (Lean.mkConst ``Trans.trans [u, v, w, u_1, u_2, u_3]) #[Ξ±, Ξ², Ξ³, r, s, t, self, a, b, c, result, step]
42
+ let resultType := (← instantiateMVars (← inferType result)).headBeta
43
+ unless (← getCalcRelation? resultType).isSome do
44
+ throwError "invalid 'calc' step, step result is not a relation{indentExpr resultType}"
45
+ return (result, resultType)
46
+ | _ => throwError "invalid 'calc' step, failed to synthesize `Trans` instance{indentExpr selfType}{useDiagnosticMsg}"
47
+
48
+ /--
49
+ Adds a type annotation to a hole that occurs immediately at the beginning of the term.
50
+ This is so that coercions can trigger when elaborating the term.
51
+ See https://github.com/leanprover/lean4/issues/2040 for further rationale.
52
+
53
+ - `_ < 3` is annotated
54
+ - `(_) < 3` is not, because it occurs after an atom
55
+ - in `_ < _` only the first one is annotated
56
+ - `_ + 2 < 3` is annotated (not the best heuristic, ideally we'd like to annotate `_ + 2`)
57
+ - `lt _ 3` is not, because it occurs after an identifier
58
+ -/
59
+ partial def annotateFirstHoleWithType (t : Term) (type : Expr) : TermElabM Term :=
60
+ -- The state is true if we should annotate the immediately next hole with the type.
61
+ return βŸ¨β† StateT.run' (go t) true⟩
62
+ where
63
+ go (t : Syntax) := do
64
+ unless ← get do return t
65
+ match t with
66
+ | .node _ ``Lean.Parser.Term.hole _ =>
67
+ set false
68
+ `(($(⟨t⟩) : $(← exprToSyntax type)))
69
+ | .node i k as => return .node i k (← as.mapM go)
70
+ | _ => set false; return t
71
+
72
+ /-- View of a `calcStep`. -/
73
+ structure CalcStepView where
74
+ ref : Syntax
75
+ /-- A relation term like `a ≀ b` -/
76
+ term : Term
77
+ /-- A proof of `term` -/
78
+ proof : Term
79
+ deriving Inhabited
80
+
81
+ def mkCalcFirstStepView (step0 : TSyntax ``calcFirstStep) : TermElabM CalcStepView :=
82
+ withRef step0 do
83
+ match step0 with
84
+ | `(calcFirstStep| $term:term) => return { ref := step0, term := ← `($term = _), proof := ← ``(rfl)}
85
+ | `(calcFirstStep| $term := $proof) => return { ref := step0, term, proof}
86
+ | _ => throwUnsupportedSyntax
87
+
88
+ def mkCalcStepViews (steps : TSyntax ``calcSteps) : TermElabM (Array CalcStepView) :=
89
+ match steps with
90
+ | `(calcSteps|
91
+ $step0:calcFirstStep
92
+ $rest*) => do
93
+ let mut steps := #[← mkCalcFirstStepView step0]
94
+ for step in rest do
95
+ let `(calcStep| $term := $proof) := step | throwUnsupportedSyntax
96
+ steps := steps.push { ref := step, term, proof }
97
+ return steps
98
+ | _ => throwUnsupportedSyntax
99
+
100
+ def elabCalcSteps (steps : Array CalcStepView) : TermElabM (Expr Γ— Expr) := do
101
+ let mut result? := none
102
+ let mut prevRhs? := none
103
+ for step in steps do
104
+ let type ← elabType <| ← do
105
+ if let some prevRhs := prevRhs? then
106
+ annotateFirstHoleWithType step.term (← inferType prevRhs)
107
+ else
108
+ pure step.term
109
+ let some (_, lhs, rhs) ← getCalcRelation? type |
110
+ throwErrorAt step.term "invalid 'calc' step, relation expected{indentExpr type}"
111
+ if let some prevRhs := prevRhs? then
112
+ unless (← isDefEqGuarded lhs prevRhs) do
113
+ throwErrorAt step.term "\
114
+ invalid 'calc' step, left-hand side is{indentD m!"{lhs} : {← inferType lhs}"}\n\
115
+ but previous right-hand side is{indentD m!"{prevRhs} : {← inferType prevRhs}"}"
116
+ let proof ← withFreshMacroScope do elabTermEnsuringType step.proof type
117
+ result? := some <| ← do
118
+ if let some (result, resultType) := result? then
119
+ synthesizeSyntheticMVarsUsingDefault
120
+ withRef step.term do mkCalcTrans result resultType proof type
121
+ else
122
+ pure (proof, type)
123
+ prevRhs? := rhs
124
+ synthesizeSyntheticMVarsUsingDefault
125
+ return result?.get!
126
+
127
+ def throwCalcFailure (steps : Array CalcStepView) (expectedType result : Expr) : MetaM Ξ± := do
128
+ let resultType := (← instantiateMVars (← inferType result)).headBeta
129
+ let some (r, lhs, rhs) ← getCalcRelation? resultType | unreachable!
130
+ if let some (er, elhs, erhs) ← getCalcRelation? expectedType then
131
+ if ← isDefEqGuarded r er then
132
+ let mut failed := false
133
+ unless ← isDefEqGuarded lhs elhs do
134
+ let (lhs, elhs) ← addPPExplicitToExposeDiff lhs elhs
135
+ let (lhsTy, elhsTy) ← addPPExplicitToExposeDiff (← inferType lhs) (← inferType elhs)
136
+ logErrorAt steps[0]!.term m!"\
137
+ invalid 'calc' step, left-hand side is{indentD m!"{lhs} : {lhsTy}"}\n\
138
+ but is expected to be{indentD m!"{elhs} : {elhsTy}"}"
139
+ failed := true
140
+ unless ← isDefEqGuarded rhs erhs do
141
+ let (rhs, erhs) ← addPPExplicitToExposeDiff rhs erhs
142
+ let (rhsTy, erhsTy) ← addPPExplicitToExposeDiff (← inferType rhs) (← inferType erhs)
143
+ logErrorAt steps.back!.term m!"\
144
+ invalid 'calc' step, right-hand side is{indentD m!"{rhs} : {rhsTy}"}\n\
145
+ but is expected to be{indentD m!"{erhs} : {erhsTy}"}"
146
+ failed := true
147
+ if failed then
148
+ throwAbortTerm
149
+ throwTypeMismatchError "'calc' expression" expectedType resultType result
150
+
151
+ /-!
152
+ Warning! It is *very* tempting to try to improve `calc` so that it makes use of the expected type
153
+ to unify with the LHS and RHS.
154
+ Two people have already re-implemented `elabCalcSteps` trying to do so and then reverted the changes,
155
+ not being aware of examples like https://github.com/leanprover/lean4/issues/2073
156
+
157
+ The problem is that the expected type might need to be unfolded to get an accurate LHS and RHS.
158
+ (Consider `≀` vs `β‰₯`. Users expect to be able to use `calc` to prove `β‰₯` using chained `≀`!)
159
+ Furthermore, the types of the LHS and RHS do not need to be the same (consider `x ∈ S` as a relation),
160
+ so we also cannot use the expected LHS and RHS as type hints.
161
+ -/
162
+
163
+ /-- Elaborator for the `calc` term mode variant. -/
164
+ @[builtin_term_elab Lean.calc]
165
+ def elabCalc : TermElab
166
+ | `(calc%$tk $steps:calcSteps), expectedType? => withRef tk do
167
+ let steps ← mkCalcStepViews steps
168
+ let (result, _) ← elabCalcSteps steps
169
+ ensureHasTypeWithErrorMsgs expectedType? result
170
+ (mkImmedErrorMsg := fun _ => throwCalcFailure steps)
171
+ (mkErrorMsg := fun _ => throwCalcFailure steps)
172
+ | _, _ => throwUnsupportedSyntax
173
+
174
+ end Lean.Elab.Term
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/CheckTactic.lean ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Lean FRO. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Joe Hendrix
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Tactic.ElabTerm
8
+ import Lean.Elab.Command
9
+ import Lean.Elab.Tactic.Meta
10
+ import Lean.Meta.CheckTactic
11
+
12
+ /-!
13
+ Commands to validate tactic results.
14
+ -/
15
+
16
+ namespace Lean.Elab.CheckTactic
17
+
18
+ open Lean.Meta CheckTactic
19
+ open Lean.Elab.Tactic
20
+ open Lean.Elab.Term
21
+ open Lean.Elab.Command
22
+
23
+ @[builtin_command_elab Lean.Parser.checkTactic]
24
+ def elabCheckTactic : CommandElab := fun stx => do
25
+ let `(#check_tactic $t ~> $result by $tac) := stx | throwUnsupportedSyntax
26
+ withoutModifyingEnv $ do
27
+ runTermElabM $ fun _vars => do
28
+ let u ← withSynthesize (postpone := .no) <| Lean.Elab.Term.elabTerm t none
29
+ let type ← inferType u
30
+ let checkGoalType ← mkCheckGoalType u type
31
+ let mvar ← mkFreshExprMVar (.some checkGoalType)
32
+ let expTerm ← Lean.Elab.Term.elabTerm result (.some type)
33
+ let (goals, _) ← Lean.Elab.runTactic mvar.mvarId! tac.raw
34
+ match goals with
35
+ | [] =>
36
+ throwErrorAt stx
37
+ m!"{tac} closed goal, but is expected to reduce to {indentExpr expTerm}."
38
+ | [next] => do
39
+ let (val, _, _) ← matchCheckGoalType stx (←next.getType)
40
+ if !(← Meta.withReducible <| isDefEq val expTerm) then
41
+ let (val, expTerm) ← addPPExplicitToExposeDiff val expTerm
42
+ throwErrorAt stx
43
+ m!"Term reduces to{indentExpr val}\nbut is expected to reduce to {indentExpr expTerm}"
44
+ | _ => do
45
+ throwErrorAt stx
46
+ m!"{tac} produced multiple goals, but is expected to reduce to {indentExpr expTerm}."
47
+
48
+ @[builtin_command_elab Lean.Parser.checkTacticFailure]
49
+ def elabCheckTacticFailure : CommandElab := fun stx => do
50
+ let `(#check_tactic_failure $t by $tactic) := stx | throwUnsupportedSyntax
51
+ withoutModifyingEnv $ do
52
+ runTermElabM $ fun _vars => do
53
+ let val ← Lean.Elab.Term.elabTerm t none
54
+ let type ← inferType val
55
+ let checkGoalType ← mkCheckGoalType val type
56
+ let mvar ← mkFreshExprMVar (.some checkGoalType)
57
+ let act := Lean.Elab.runTactic mvar.mvarId! tactic.raw
58
+ match ← try (Term.withoutErrToSorry (some <$> act)) catch _ => pure none with
59
+ | none =>
60
+ pure ()
61
+ | some (gls, _) =>
62
+ let ppGoal (g : MVarId) := do
63
+ let (val, _type, _u) ← matchCheckGoalType stx (← g.getType)
64
+ pure m!"{indentExpr val}"
65
+ let msg ←
66
+ match gls with
67
+ | [] => pure m!"{tactic} expected to fail on {t}, but closed goal."
68
+ | [g] =>
69
+ pure <| m!"{tactic} expected to fail on {t}, but returned: {←ppGoal g}"
70
+ | gls =>
71
+ let app m g := do pure <| m ++ (←ppGoal g)
72
+ let init := m!"{tactic} expected to fail on {t}, but returned goals:"
73
+ gls.foldlM (init := init) app
74
+ throwErrorAt stx msg
75
+
76
+ @[builtin_macro Lean.Parser.checkSimp]
77
+ def expandCheckSimp : Macro := fun stx => do
78
+ let `(#check_simp $t ~> $exp) := stx | Macro.throwUnsupported
79
+ `(command|#check_tactic $t ~> $exp by simp)
80
+
81
+ @[builtin_macro Lean.Parser.checkSimpFailure]
82
+ def expandCheckSimpFailure : Macro := fun stx => do
83
+ let `(#check_simp $t !~>) := stx | Macro.throwUnsupported
84
+ `(command|#check_tactic_failure $t by simp)
85
+
86
+ end Lean.Elab.CheckTactic
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Command.lean ADDED
@@ -0,0 +1,891 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2019 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Gabriel Ebner
5
+ -/
6
+ prelude
7
+ import Lean.Meta.Diagnostics
8
+ import Lean.Elab.Binders
9
+ import Lean.Elab.SyntheticMVars
10
+ import Lean.Elab.SetOption
11
+ import Lean.Language.Basic
12
+ import Lean.Meta.ForEachExpr
13
+
14
+ namespace Lean.Elab.Command
15
+
16
+ /--
17
+ A `Scope` records the part of the `CommandElabM` state that respects scoping,
18
+ such as the data for `universe`, `open`, and `variable` declarations, the current namespace,
19
+ and currently enabled options.
20
+ The `CommandElabM` state contains a stack of scopes, and only the top `Scope`
21
+ on the stack is read from or modified. There is always at least one `Scope` on the stack,
22
+ even outside any `section` or `namespace`, and each new pushed `Scope`
23
+ starts as a modified copy of the previous top scope.
24
+ -/
25
+ structure Scope where
26
+ /--
27
+ The component of the `namespace` or `section` that this scope is associated to.
28
+ For example, `section a.b.c` and `namespace a.b.c` each create three scopes with headers
29
+ named `a`, `b`, and `c`.
30
+ This is used for checking the `end` command. The "base scope" has `""` as its header.
31
+ -/
32
+ header : String
33
+ /--
34
+ The current state of all set options at this point in the scope. Note that this is the
35
+ full current set of options and does *not* simply contain the options set
36
+ while this scope has been active.
37
+ -/
38
+ opts : Options := {}
39
+ /-- The current namespace. The top-level namespace is represented by `Name.anonymous`. -/
40
+ currNamespace : Name := Name.anonymous
41
+ /-- All currently `open`ed namespaces and names. -/
42
+ openDecls : List OpenDecl := []
43
+ /-- The current list of names for universe level variables to use for new declarations. This is managed by the `universe` command. -/
44
+ levelNames : List Name := []
45
+ /--
46
+ The current list of binders to use for new declarations.
47
+ This is managed by the `variable` command.
48
+ Each binder is represented in `Syntax` form, and it is re-elaborated
49
+ within each command that uses this information.
50
+
51
+ This is also used by commands, such as `#check`, to create an initial local context,
52
+ even if they do not work with binders per se.
53
+ -/
54
+ varDecls : Array (TSyntax ``Parser.Term.bracketedBinder) := #[]
55
+ /--
56
+ Globally unique internal identifiers for the `varDecls`.
57
+ There is one identifier per variable introduced by the binders
58
+ (recall that a binder such as `(a b c : Ty)` can produce more than one variable),
59
+ and each identifier is the user-provided variable name with a macro scope.
60
+ This is used by `TermElabM` in `Lean.Elab.Term.Context` to help with processing macros
61
+ that capture these variables.
62
+ -/
63
+ varUIds : Array Name := #[]
64
+ /-- `include`d section variable names (from `varUIds`) -/
65
+ includedVars : List Name := []
66
+ /-- `omit`ted section variable names (from `varUIds`) -/
67
+ omittedVars : List Name := []
68
+ /--
69
+ If true (default: false), all declarations that fail to compile
70
+ automatically receive the `noncomputable` modifier.
71
+ A scope with this flag set is created by `noncomputable section`.
72
+
73
+ Recall that a new scope inherits all values from its parent scope,
74
+ so all sections and namespaces nested within a `noncomputable` section also have this flag set.
75
+ -/
76
+ isNoncomputable : Bool := false
77
+ isPublic : Bool := false
78
+ /--
79
+ Attributes that should be applied to all matching declaration in the section. Inherited from
80
+ parent scopes.
81
+ -/
82
+ attrs : List (TSyntax ``Parser.Term.attrInstance) := []
83
+ deriving Inhabited
84
+
85
+ structure State where
86
+ env : Environment
87
+ messages : MessageLog := {}
88
+ scopes : List Scope := [{ header := "" }]
89
+ nextMacroScope : Nat := firstFrontendMacroScope + 1
90
+ maxRecDepth : Nat
91
+ ngen : NameGenerator := {}
92
+ auxDeclNGen : DeclNameGenerator := {}
93
+ infoState : InfoState := {}
94
+ traceState : TraceState := {}
95
+ snapshotTasks : Array (Language.SnapshotTask Language.SnapshotTree) := #[]
96
+ deriving Nonempty
97
+
98
+ structure Context where
99
+ fileName : String
100
+ fileMap : FileMap
101
+ currRecDepth : Nat := 0
102
+ cmdPos : String.Pos := 0
103
+ macroStack : MacroStack := []
104
+ currMacroScope : MacroScope := firstFrontendMacroScope
105
+ ref : Syntax := Syntax.missing
106
+ /--
107
+ Snapshot for incremental reuse and reporting of command elaboration. Currently only used for
108
+ (mutual) defs and contained tactics, in which case the `DynamicSnapshot` is a
109
+ `HeadersParsedSnapshot`.
110
+
111
+ Definitely resolved in `Lean.Elab.Command.elabCommandTopLevel`.
112
+
113
+ Invariant: if the bundle's `old?` is set, the context and state at the beginning of current and
114
+ old elaboration are identical.
115
+ -/
116
+ snap? : Option (Language.SnapshotBundle Language.DynamicSnapshot)
117
+ /-- Cancellation token forwarded to `Core.cancelTk?`. -/
118
+ cancelTk? : Option IO.CancelToken
119
+ /--
120
+ If set (when `showPartialSyntaxErrors` is not set and parsing failed), suppresses most elaboration
121
+ errors; see also `logMessage` below.
122
+ -/
123
+ suppressElabErrors : Bool := false
124
+
125
+ abbrev CommandElabM := ReaderT Context $ StateRefT State $ EIO Exception
126
+ abbrev CommandElab := Syntax β†’ CommandElabM Unit
127
+ structure Linter where
128
+ run : Syntax β†’ CommandElabM Unit
129
+ name : Name := by exact decl_name%
130
+
131
+ /-
132
+ Make the compiler generate specialized `pure`/`bind` so we do not have to optimize through the
133
+ whole monad stack at every use site. May eventually be covered by `deriving`.
134
+
135
+ Remark: see comment at TermElabM
136
+ -/
137
+ @[always_inline]
138
+ instance : Monad CommandElabM := let i := inferInstanceAs (Monad CommandElabM); { pure := i.pure, bind := i.bind }
139
+
140
+ /--
141
+ Like `Core.tryCatchRuntimeEx`; runtime errors are generally used to abort term elaboration, so we do
142
+ want to catch and process them at the command level.
143
+ -/
144
+ @[inline] protected def tryCatch (x : CommandElabM Ξ±) (h : Exception β†’ CommandElabM Ξ±) :
145
+ CommandElabM Ξ± := do
146
+ try
147
+ x
148
+ catch ex =>
149
+ if ex.isInterrupt then
150
+ throw ex
151
+ else
152
+ h ex
153
+
154
+ instance : MonadExceptOf Exception CommandElabM where
155
+ throw := throw
156
+ tryCatch := Command.tryCatch
157
+
158
+ def mkState (env : Environment) (messages : MessageLog := {}) (opts : Options := {}) : State := {
159
+ env := env
160
+ messages := messages
161
+ scopes := [{ header := "", opts }]
162
+ maxRecDepth := maxRecDepth.get opts
163
+ -- Outside of declarations, fall back to a module-specific prefix
164
+ auxDeclNGen := { namePrefix := mkPrivateName env .anonymous }
165
+ }
166
+
167
+ /- Linters should be loadable as plugins, so store in a global IO ref instead of an attribute managed by the
168
+ environment (which only contains `import`ed objects). -/
169
+ builtin_initialize lintersRef : IO.Ref (Array Linter) ← IO.mkRef #[]
170
+ builtin_initialize registerTraceClass `Elab.lint
171
+
172
+ def addLinter (l : Linter) : IO Unit := do
173
+ let ls ← lintersRef.get
174
+ lintersRef.set (ls.push l)
175
+
176
+ instance : MonadInfoTree CommandElabM where
177
+ getInfoState := return (← get).infoState
178
+ modifyInfoState f := modify fun s => { s with infoState := f s.infoState }
179
+
180
+ instance : MonadEnv CommandElabM where
181
+ getEnv := do pure (← get).env
182
+ modifyEnv f := modify fun s => { s with env := f s.env }
183
+
184
+ @[always_inline]
185
+ instance : MonadOptions CommandElabM where
186
+ getOptions := do pure (← get).scopes.head!.opts
187
+
188
+ protected def getRef : CommandElabM Syntax :=
189
+ return (← read).ref
190
+
191
+ instance : AddMessageContext CommandElabM where
192
+ addMessageContext := addMessageContextPartial
193
+
194
+ instance : MonadRef CommandElabM where
195
+ getRef := Command.getRef
196
+ withRef ref x := withReader (fun ctx => { ctx with ref := ref }) x
197
+
198
+ instance : MonadTrace CommandElabM where
199
+ getTraceState := return (← get).traceState
200
+ modifyTraceState f := modify fun s => { s with traceState := f s.traceState }
201
+
202
+ instance : AddErrorMessageContext CommandElabM where
203
+ add ref msg := do
204
+ let ctx ← read
205
+ let ref := getBetterRef ref ctx.macroStack
206
+ let msg ← addMessageContext msg
207
+ let msg ← addMacroStack msg ctx.macroStack
208
+ return (ref, msg)
209
+
210
+ instance : MonadDeclNameGenerator CommandElabM where
211
+ getDeclNGen := return (← get).auxDeclNGen
212
+ setDeclNGen ngen := modify fun s => { s with auxDeclNGen := ngen }
213
+
214
+ private def runCore (x : CoreM Ξ±) : CommandElabM Ξ± := do
215
+ let s ← get
216
+ let ctx ← read
217
+ let heartbeats ← IO.getNumHeartbeats
218
+ let env := Kernel.resetDiag s.env
219
+ let scope := s.scopes.head!
220
+ let coreCtx : Core.Context := {
221
+ fileName := ctx.fileName
222
+ fileMap := ctx.fileMap
223
+ currRecDepth := ctx.currRecDepth
224
+ maxRecDepth := s.maxRecDepth
225
+ ref := ctx.ref
226
+ currNamespace := scope.currNamespace
227
+ openDecls := scope.openDecls
228
+ initHeartbeats := heartbeats
229
+ currMacroScope := ctx.currMacroScope
230
+ options := scope.opts
231
+ cancelTk? := ctx.cancelTk?
232
+ suppressElabErrors := ctx.suppressElabErrors }
233
+ let x : EIO _ _ := x.run coreCtx {
234
+ env
235
+ ngen := s.ngen
236
+ auxDeclNGen := s.auxDeclNGen
237
+ nextMacroScope := s.nextMacroScope
238
+ infoState.enabled := s.infoState.enabled
239
+ traceState := s.traceState
240
+ snapshotTasks := s.snapshotTasks
241
+ }
242
+ let (ea, coreS) ← liftM x
243
+ modify fun s => { s with
244
+ env := coreS.env
245
+ nextMacroScope := coreS.nextMacroScope
246
+ ngen := coreS.ngen
247
+ auxDeclNGen := coreS.auxDeclNGen
248
+ infoState.trees := s.infoState.trees.append coreS.infoState.trees
249
+ -- we assume substitution of `assignment` has already happened, but for lazy assignments we only
250
+ -- do it at the very end
251
+ infoState.lazyAssignment := coreS.infoState.lazyAssignment
252
+ traceState.traces := coreS.traceState.traces.map fun t => { t with ref := replaceRef t.ref ctx.ref }
253
+ snapshotTasks := coreS.snapshotTasks
254
+ messages := s.messages ++ coreS.messages
255
+ }
256
+ return ea
257
+
258
+ def liftCoreM (x : CoreM Ξ±) : CommandElabM Ξ± := do
259
+ MonadExcept.ofExcept (← runCore (observing x))
260
+
261
+ @[inline] def liftIO {Ξ±} (x : IO Ξ±) : CommandElabM Ξ± := do
262
+ let ctx ← read
263
+ IO.toEIO (fun (ex : IO.Error) => Exception.error ctx.ref ex.toString) x
264
+
265
+ instance : MonadLiftT IO CommandElabM where
266
+ monadLift := liftIO
267
+
268
+ /-- Return the current scope. -/
269
+ def getScope : CommandElabM Scope := do pure (← get).scopes.head!
270
+
271
+ instance : MonadResolveName CommandElabM where
272
+ getCurrNamespace := return (← getScope).currNamespace
273
+ getOpenDecls := return (← getScope).openDecls
274
+
275
+ instance : MonadLog CommandElabM where
276
+ getRef := getRef
277
+ getFileMap := return (← read).fileMap
278
+ getFileName := return (← read).fileName
279
+ hasErrors := return (← get).messages.hasErrors
280
+ logMessage msg := do
281
+ if (← read).suppressElabErrors then
282
+ -- discard elaboration errors on parse error
283
+ unless msg.data.hasTag (Β· matches `trace) do
284
+ return
285
+ let currNamespace ← getCurrNamespace
286
+ let openDecls ← getOpenDecls
287
+ let msg := { msg with data := MessageData.withNamingContext { currNamespace := currNamespace, openDecls := openDecls } msg.data }
288
+ modify fun s => { s with messages := s.messages.add msg }
289
+
290
+ def runLinters (stx : Syntax) : CommandElabM Unit := do
291
+ profileitM Exception "linting" (← getOptions) do
292
+ withTraceNode `Elab.lint (fun _ => return m!"running linters") do
293
+ let linters ← lintersRef.get
294
+ unless linters.isEmpty do
295
+ for linter in linters do
296
+ withTraceNode `Elab.lint (fun _ => return m!"running linter: {.ofConstName linter.name}")
297
+ (tag := linter.name.toString) do
298
+ let savedState ← get
299
+ try
300
+ linter.run stx
301
+ catch ex =>
302
+ match ex with
303
+ | Exception.error ref msg =>
304
+ logException (.error ref m!"linter {.ofConstName linter.name} failed: {msg}")
305
+ | Exception.internal _ _ =>
306
+ logException ex
307
+ finally
308
+ -- TODO: it would be good to preserve even more state (#4363) but preserving info
309
+ -- trees currently breaks from linters adding context-less info nodes
310
+ modify fun s => { savedState with messages := s.messages, traceState := s.traceState }
311
+
312
+ /--
313
+ Catches and logs exceptions occurring in `x`. Unlike `try catch` in `CommandElabM`, this function
314
+ catches interrupt exceptions as well and thus is intended for use at the top level of elaboration.
315
+ Interrupt and abort exceptions are caught but not logged.
316
+ -/
317
+ @[inline] def withLoggingExceptions (x : CommandElabM Unit) : CommandElabM Unit := fun ctx ref =>
318
+ EIO.catchExceptions (withLogging x ctx ref) (fun _ => pure ())
319
+
320
+ @[inherit_doc Core.wrapAsync]
321
+ def wrapAsync {Ξ± Ξ² : Type} (act : Ξ± β†’ CommandElabM Ξ²) (cancelTk? : Option IO.CancelToken) :
322
+ CommandElabM (Ξ± β†’ EIO Exception Ξ²) := do
323
+ let ctx ← read
324
+ let ctx := { ctx with cancelTk? }
325
+ let (childNGen, parentNGen) := (← getDeclNGen).mkChild
326
+ setDeclNGen parentNGen
327
+ let st ← get
328
+ let st := { st with auxDeclNGen := childNGen }
329
+ return (act Β· |>.run ctx |>.run' st)
330
+
331
+ open Language in
332
+ @[inherit_doc Core.wrapAsyncAsSnapshot]
333
+ -- `CoreM` and `CommandElabM` are too different to meaningfully share this code
334
+ def wrapAsyncAsSnapshot {Ξ± : Type} (act : Ξ± β†’ CommandElabM Unit) (cancelTk? : Option IO.CancelToken)
335
+ (desc : String := by exact decl_name%.toString) :
336
+ CommandElabM (Ξ± β†’ BaseIO SnapshotTree) := do
337
+ let f ← wrapAsync (cancelTk? := cancelTk?) fun a => do
338
+ IO.FS.withIsolatedStreams (isolateStderr := Core.stderrAsMessages.get (← getOptions)) do
339
+ let tid ← IO.getTID
340
+ -- reset trace state and message log so as not to report them twice
341
+ modify fun st => { st with
342
+ messages := st.messages.markAllReported
343
+ traceState := { tid }
344
+ snapshotTasks := #[]
345
+ }
346
+ try
347
+ withTraceNode `Elab.async (fun _ => return desc) do
348
+ act a
349
+ catch e =>
350
+ logError e.toMessageData
351
+ finally
352
+ addTraceAsMessages
353
+ get
354
+ let ctx ← read
355
+ return fun a => do
356
+ match (← (f a).toBaseIO) with
357
+ | .ok (output, st) =>
358
+ let mut msgs := st.messages
359
+ if !output.isEmpty then
360
+ msgs := msgs.add {
361
+ fileName := ctx.fileName
362
+ severity := MessageSeverity.information
363
+ pos := ctx.fileMap.toPosition <| ctx.ref.getPos?.getD 0
364
+ data := output
365
+ }
366
+ return .mk {
367
+ desc
368
+ diagnostics := (← Language.Snapshot.Diagnostics.ofMessageLog msgs)
369
+ traces := st.traceState
370
+ } st.snapshotTasks
371
+ -- interrupt or abort exception as `try catch` above should have caught any others
372
+ | .error _ => default
373
+
374
+ @[inherit_doc Core.logSnapshotTask]
375
+ def logSnapshotTask (task : Language.SnapshotTask Language.SnapshotTree) : CommandElabM Unit :=
376
+ modify fun s => { s with snapshotTasks := s.snapshotTasks.push task }
377
+
378
+ open Language in
379
+ def runLintersAsync (stx : Syntax) : CommandElabM Unit := do
380
+ if !Elab.async.get (← getOptions) then
381
+ withoutModifyingEnv do
382
+ runLinters stx
383
+ return
384
+
385
+ -- linters should have access to the complete info tree and message log
386
+ let mut snaps := (← get).snapshotTasks
387
+ if let some elabSnap := (← read).snap? then
388
+ snaps := snaps.push { stx? := none, cancelTk? := none, task := elabSnap.new.result!.map (sync := true) toSnapshotTree }
389
+ let tree := SnapshotTree.mk { diagnostics := .empty } snaps
390
+ let treeTask ← tree.waitAll
391
+
392
+ -- We only start one task for all linters for now as most linters are fast and we simply want
393
+ -- to unblock elaboration of the next command
394
+ let cancelTk ← IO.CancelToken.new
395
+ let lintAct ← wrapAsyncAsSnapshot (cancelTk? := cancelTk) fun infoSt => do
396
+ let messages := tree.getAll.map (Β·.diagnostics.msgLog) |>.foldl (Β· ++ Β·) .empty
397
+ -- do not double-report
398
+ let messages := messages.markAllReported
399
+ modify fun st => { st with messages := st.messages ++ messages }
400
+ modifyInfoState fun _ => infoSt
401
+ runLinters stx
402
+
403
+ let task ← BaseIO.bindTask (sync := true) (t := (← getInfoState).substituteLazy) fun infoSt =>
404
+ BaseIO.mapTask (t := treeTask) fun _ =>
405
+ lintAct infoSt
406
+ logSnapshotTask { stx? := none, task, cancelTk? := cancelTk }
407
+
408
+ protected def getCurrMacroScope : CommandElabM Nat := do pure (← read).currMacroScope
409
+ protected def getMainModule : CommandElabM Name := do pure (← getEnv).mainModule
410
+
411
+ protected def withFreshMacroScope {Ξ±} (x : CommandElabM Ξ±) : CommandElabM Ξ± := do
412
+ let fresh ← modifyGet (fun st => (st.nextMacroScope, { st with nextMacroScope := st.nextMacroScope + 1 }))
413
+ withReader (fun ctx => { ctx with currMacroScope := fresh }) x
414
+
415
+ instance : MonadQuotation CommandElabM where
416
+ getCurrMacroScope := Command.getCurrMacroScope
417
+ getMainModule := Command.getMainModule
418
+ withFreshMacroScope := Command.withFreshMacroScope
419
+
420
+ /--
421
+ Registers a command elaborator for the given syntax node kind.
422
+
423
+ A command elaborator should have type `Lean.Elab.Command.CommandElab` (which is
424
+ `Lean.Syntax β†’ Lean.Elab.Term.CommandElabM Unit`), i.e. should take syntax of the given syntax
425
+ node kind as a parameter and perform an action.
426
+
427
+ The `elab_rules` and `elab` commands should usually be preferred over using this attribute
428
+ directly.
429
+ -/
430
+ @[builtin_doc]
431
+ unsafe builtin_initialize commandElabAttribute : KeyedDeclsAttribute CommandElab ←
432
+ mkElabAttribute CommandElab `builtin_command_elab `command_elab `Lean.Parser.Command `Lean.Elab.Command.CommandElab "command"
433
+
434
+ private def mkInfoTree (elaborator : Name) (stx : Syntax) (trees : PersistentArray InfoTree) : CommandElabM InfoTree := do
435
+ let ctx ← read
436
+ let s ← get
437
+ let scope := s.scopes.head!
438
+ let tree := InfoTree.node (Info.ofCommandInfo { elaborator, stx }) trees
439
+ let ctx := PartialContextInfo.commandCtx {
440
+ env := s.env, fileMap := ctx.fileMap, mctx := {}, currNamespace := scope.currNamespace,
441
+ openDecls := scope.openDecls, options := scope.opts, ngen := s.ngen
442
+ }
443
+ return InfoTree.context ctx tree
444
+
445
+ /--
446
+ Disables incremental command reuse *and* reporting for `act` if `cond` is true by setting
447
+ `Context.snap?` to `none`.
448
+ -/
449
+ def withoutCommandIncrementality (cond : Bool) (act : CommandElabM Ξ±) : CommandElabM Ξ± := do
450
+ let opts ← getOptions
451
+ withReader (fun ctx => { ctx with snap? := ctx.snap?.filter fun snap => Id.run do
452
+ if let some old := snap.old? then
453
+ if cond && opts.getBool `trace.Elab.reuse then
454
+ dbg_trace "reuse stopped: guard failed at {old.stx}"
455
+ return !cond
456
+ }) act
457
+
458
+ private def elabCommandUsing (s : State) (stx : Syntax) : List (KeyedDeclsAttribute.AttributeEntry CommandElab) β†’ CommandElabM Unit
459
+ | [] => withInfoTreeContext (mkInfoTree := mkInfoTree `no_elab stx) <| throwError "unexpected syntax{indentD stx}"
460
+ | (elabFn::elabFns) =>
461
+ catchInternalId unsupportedSyntaxExceptionId
462
+ (do
463
+ -- prevent unsupported commands from accidentally accessing `Context.snap?` (e.g. by nested
464
+ -- supported commands)
465
+ withoutCommandIncrementality (!(← isIncrementalElab elabFn.declName)) do
466
+ withInfoTreeContext (mkInfoTree := mkInfoTree elabFn.declName stx) do
467
+ elabFn.value stx)
468
+ (fun _ => do set s; elabCommandUsing s stx elabFns)
469
+
470
+ /-- Elaborate `x` with `stx` on the macro stack -/
471
+ def withMacroExpansion (beforeStx afterStx : Syntax) (x : CommandElabM Ξ±) : CommandElabM Ξ± :=
472
+ withInfoContext (mkInfo := pure <| .ofMacroExpansionInfo { stx := beforeStx, output := afterStx, lctx := .empty }) do
473
+ withReader (fun ctx => { ctx with macroStack := { before := beforeStx, after := afterStx } :: ctx.macroStack }) x
474
+
475
+ instance : MonadMacroAdapter CommandElabM where
476
+ getCurrMacroScope := getCurrMacroScope
477
+ getNextMacroScope := return (← get).nextMacroScope
478
+ setNextMacroScope next := modify fun s => { s with nextMacroScope := next }
479
+
480
+ instance : MonadRecDepth CommandElabM where
481
+ withRecDepth d x := withReader (fun ctx => { ctx with currRecDepth := d }) x
482
+ getRecDepth := return (← read).currRecDepth
483
+ getMaxRecDepth := return (← get).maxRecDepth
484
+
485
+ builtin_initialize registerTraceClass `Elab.command
486
+
487
+ open Language in
488
+ /-- Snapshot after macro expansion of a command. -/
489
+ structure MacroExpandedSnapshot extends Snapshot where
490
+ /-- The declaration name of the macro. -/
491
+ macroDecl : Name
492
+ /-- The expanded syntax tree. -/
493
+ newStx : Syntax
494
+ /-- `State.nextMacroScope` after expansion. -/
495
+ newNextMacroScope : Nat
496
+ /-- Whether any traces were present after expansion. -/
497
+ hasTraces : Bool
498
+ /--
499
+ Follow-up elaboration snapshots, one per command if `newStx` is a sequence of commands.
500
+ -/
501
+ next : Array (SnapshotTask DynamicSnapshot)
502
+ deriving TypeName
503
+ open Language in
504
+ instance : ToSnapshotTree MacroExpandedSnapshot where
505
+ toSnapshotTree s := ⟨s.toSnapshot, s.next.map (·.map (sync := true) toSnapshotTree)⟩
506
+
507
+ partial def elabCommand (stx : Syntax) : CommandElabM Unit :=
508
+ try
509
+ go
510
+ finally
511
+ addTraceAsMessages
512
+ where go := do
513
+ withLogging <| withRef stx <| withIncRecDepth <| withFreshMacroScope do
514
+ match stx with
515
+ | Syntax.node _ k args =>
516
+ if k == nullKind then
517
+ -- list of commands => elaborate in order
518
+ -- The parser will only ever return a single command at a time, but syntax quotations can return multiple ones
519
+ -- Incrementality is currently limited to the common case where the sequence is the direct
520
+ -- output of a macro, see below.
521
+ withoutCommandIncrementality true do
522
+ args.forM elabCommand
523
+ else withTraceNode `Elab.command (fun _ => return stx) (tag :=
524
+ -- special case: show actual declaration kind for `declaration` commands
525
+ (if stx.isOfKind ``Parser.Command.declaration then stx[1] else stx).getKind.toString) do
526
+ let s ← get
527
+ match (← liftMacroM <| expandMacroImpl? s.env stx) with
528
+ | some (decl, stxNew?) =>
529
+ withInfoTreeContext (mkInfoTree := mkInfoTree decl stx) do
530
+ let stxNew ← liftMacroM <| liftExcept stxNew?
531
+ withMacroExpansion stx stxNew do
532
+ -- Support incrementality; see also Note [Incremental Macros]
533
+ if let some snap := (←read).snap? then
534
+ -- Unpack nested commands; see `MacroExpandedSnapshot.next`
535
+ let cmds := if stxNew.isOfKind nullKind then stxNew.getArgs else #[stxNew]
536
+ let nextMacroScope := (← get).nextMacroScope
537
+ let hasTraces := (← getTraceState).traces.size > 0
538
+ let oldSnap? := do
539
+ let oldSnap ← snap.old?
540
+ let oldSnap ← oldSnap.val.get.toTyped? MacroExpandedSnapshot
541
+ guard <| oldSnap.macroDecl == decl && oldSnap.newNextMacroScope == nextMacroScope
542
+ -- check absence of traces; see Note [Incremental Macros]
543
+ guard <| !oldSnap.hasTraces && !hasTraces
544
+ return oldSnap
545
+ if snap.old?.isSome && oldSnap?.isNone then
546
+ snap.old?.forM (Β·.val.cancelRec)
547
+ let oldCmds? := oldSnap?.map fun old =>
548
+ if old.newStx.isOfKind nullKind then old.newStx.getArgs else #[old.newStx]
549
+ let cmdPromises ← cmds.mapM fun _ => IO.Promise.new
550
+ let cancelTk? := (← read).cancelTk?
551
+ snap.new.resolve <| .ofTyped {
552
+ diagnostics := .empty
553
+ macroDecl := decl
554
+ newStx := stxNew
555
+ newNextMacroScope := nextMacroScope
556
+ hasTraces
557
+ next := Array.zipWith (fun cmdPromise cmd =>
558
+ { stx? := some cmd, task := cmdPromise.resultD default, cancelTk? }) cmdPromises cmds
559
+ : MacroExpandedSnapshot
560
+ }
561
+ -- After the first command whose syntax tree changed, we must disable
562
+ -- incremental reuse
563
+ let mut reusedCmds := true
564
+ let opts ← getOptions
565
+ -- For each command, associate it with new promise and old snapshot, if any, and
566
+ -- elaborate recursively
567
+ for cmd in cmds, cmdPromise in cmdPromises, i in [0:cmds.size] do
568
+ let oldCmd? := oldCmds?.bind (Β·[i]?)
569
+ withReader ({ Β· with snap? := some {
570
+ new := cmdPromise
571
+ old? := do
572
+ guard reusedCmds
573
+ let old ← oldSnap?
574
+ return { stx := (← oldCmd?), val := (← old.next[i]?) }
575
+ } }) do
576
+ if oldSnap?.isSome && (← read).snap?.isNone then
577
+ oldSnap?.bind (Β·.next[i]?) |>.forM (Β·.cancelRec)
578
+ elabCommand cmd
579
+ -- Resolve promise for commands not supporting incrementality; waiting for
580
+ -- `withAlwaysResolvedPromises` to do this could block reporting by later
581
+ -- commands
582
+ cmdPromise.resolve default
583
+ reusedCmds := reusedCmds && oldCmd?.any (Β·.eqWithInfoAndTraceReuse opts cmd)
584
+ else
585
+ elabCommand stxNew
586
+ | _ =>
587
+ match commandElabAttribute.getEntries s.env k with
588
+ | [] =>
589
+ withInfoTreeContext (mkInfoTree := mkInfoTree `no_elab stx) <|
590
+ throwError "elaboration function for '{k}' has not been implemented"
591
+ | elabFns => elabCommandUsing s stx elabFns
592
+ | _ =>
593
+ withInfoTreeContext (mkInfoTree := mkInfoTree `no_elab stx) <|
594
+ throwError "unexpected command"
595
+
596
+ builtin_initialize registerTraceClass `Elab.input
597
+
598
+ /-- Option for showing elaboration errors from partial syntax errors. -/
599
+ register_builtin_option showPartialSyntaxErrors : Bool := {
600
+ defValue := false
601
+ descr := "show elaboration errors from partial syntax trees (i.e. after parser recovery)"
602
+ }
603
+
604
+ builtin_initialize
605
+ registerTraceClass `Elab.info
606
+ registerTraceClass `Elab.snapshotTree
607
+
608
+ /--
609
+ `elabCommand` wrapper that should be used for the initial invocation, not for recursive calls after
610
+ macro expansion etc.
611
+ -/
612
+ def elabCommandTopLevel (stx : Syntax) : CommandElabM Unit := withRef stx do profileitM Exception "elaboration" (← getOptions) do
613
+ withReader ({ Β· with suppressElabErrors :=
614
+ stx.hasMissing && !showPartialSyntaxErrors.get (← getOptions) }) do
615
+ let initMsgs ← modifyGet fun st => (st.messages, { st with messages := {} })
616
+ let initInfoTrees ← getResetInfoTrees
617
+ try
618
+ try
619
+ -- We should *not* factor out `elabCommand`'s `withLogging` to here since it would make its error
620
+ -- recovery more coarse. In particular, if `c` in `set_option ... in $c` fails, the remaining
621
+ -- `end` command of the `in` macro would be skipped and the option would be leaked to the outside!
622
+ elabCommand stx
623
+ finally
624
+ -- Make sure `snap?` is definitely resolved; we do not use it for reporting as `#guard_msgs` may
625
+ -- be the caller of this function and add new messages and info trees
626
+ if let some snap := (← read).snap? then
627
+ snap.new.resolve default
628
+
629
+ -- Run the linters, unless `#guard_msgs` is present, which is special and runs `elabCommandTopLevel` itself,
630
+ -- so it is a "super-top-level" command. This is the only command that does this, so we just special case it here
631
+ -- rather than engineer a general solution.
632
+ unless (stx.find? (Β·.isOfKind ``Lean.guardMsgsCmd)).isSome do
633
+ withLogging do
634
+ runLintersAsync stx
635
+ finally
636
+ let msgs := (← get).messages
637
+ modify fun st => { st with
638
+ messages := initMsgs ++ msgs
639
+ infoState := { st.infoState with trees := initInfoTrees ++ st.infoState.trees }
640
+ }
641
+
642
+ /-- Adapt a syntax transformation to a regular, command-producing elaborator. -/
643
+ def adaptExpander (exp : Syntax β†’ CommandElabM Syntax) : CommandElab := fun stx => do
644
+ let stx' ← exp stx
645
+ withMacroExpansion stx stx' <| elabCommand stx'
646
+
647
+ private def getVarDecls (s : State) : Array Syntax :=
648
+ s.scopes.head!.varDecls
649
+
650
+ instance {Ξ±} : Inhabited (CommandElabM Ξ±) where
651
+ default := throw default
652
+
653
+ /--
654
+ The environment linter framework needs to be able to run linters with the same context
655
+ as `liftTermElabM`, so we expose that context as a public function here.
656
+ -/
657
+ def mkMetaContext : Meta.Context := {
658
+ config := { foApprox := true, ctxApprox := true, quasiPatternApprox := true }
659
+ }
660
+
661
+ open Lean.Parser.Term in
662
+ /-- Return identifier names in the given bracketed binder. -/
663
+ def getBracketedBinderIds : Syntax β†’ CommandElabM (Array Name)
664
+ | `(bracketedBinderF|($ids* $[: $ty?]? $(_annot?)?)) => return ids.map Syntax.getId
665
+ | `(bracketedBinderF|{$ids* $[: $ty?]?}) => return ids.map Syntax.getId
666
+ | `(bracketedBinderF|⦃$ids* : $_⦄) => return ids.map Syntax.getId
667
+ | `(bracketedBinderF|[$id : $_]) => return #[id.getId]
668
+ | `(bracketedBinderF|[$_]) => return #[Name.anonymous]
669
+ | _ => throwUnsupportedSyntax
670
+
671
+ private def mkTermContext (ctx : Context) (s : State) : CommandElabM Term.Context := do
672
+ let scope := s.scopes.head!
673
+ let mut sectionVars := {}
674
+ for id in (← scope.varDecls.flatMapM getBracketedBinderIds), uid in scope.varUIds do
675
+ sectionVars := sectionVars.insert id uid
676
+ return {
677
+ macroStack := ctx.macroStack
678
+ sectionVars := sectionVars
679
+ isNoncomputableSection := scope.isNoncomputable }
680
+
681
+ /--
682
+ Lift the `TermElabM` monadic action `x` into a `CommandElabM` monadic action.
683
+
684
+ Note that `x` is executed with an empty message log. Thus, `x` cannot modify/view messages produced by
685
+ previous commands.
686
+
687
+ If you need to access the free variables corresponding to the ones declared using the `variable` command,
688
+ consider using `runTermElabM`.
689
+
690
+ Recall that `TermElabM` actions can automatically lift `MetaM` and `CoreM` actions.
691
+ Example:
692
+ ```
693
+ import Lean
694
+
695
+ open Lean Elab Command Meta
696
+
697
+ def printExpr (e : Expr) : MetaM Unit := do
698
+ IO.println s!"{← ppExpr e} : {← ppExpr (← inferType e)}"
699
+
700
+ #eval
701
+ liftTermElabM do
702
+ printExpr (mkConst ``Nat)
703
+ ```
704
+ -/
705
+ def liftTermElabM (x : TermElabM Ξ±) : CommandElabM Ξ± := do
706
+ let ctx ← read
707
+ let s ← get
708
+ -- dbg_trace "heartbeats: {heartbeats}"
709
+ let scope := s.scopes.head!
710
+ -- We execute `x` with an empty message log. Thus, `x` cannot modify/view messages produced by previous commands.
711
+ -- This is useful for implementing `runTermElabM` where we use `Term.resetMessageLog`
712
+ let x : TermElabM _ := withSaveInfoContext x
713
+ -- make sure `observing` below also catches runtime exceptions (like we do by default in
714
+ -- `CommandElabM`)
715
+ let _ := MonadAlwaysExcept.except (m := TermElabM)
716
+ let x : MetaM _ := (observing (try x finally Meta.reportDiag)).run (← mkTermContext ctx s) { levelNames := scope.levelNames }
717
+ let x : CoreM _ := x.run mkMetaContext {}
718
+ let ((ea, _), _) ← runCore x
719
+ MonadExcept.ofExcept ea
720
+
721
+ instance : MonadEval TermElabM CommandElabM where
722
+ monadEval := liftTermElabM
723
+
724
+ /--
725
+ Execute the monadic action `elabFn xs` as a `CommandElabM` monadic action, where `xs` are free variables
726
+ corresponding to all active scoped variables declared using the `variable` command.
727
+
728
+ This method is similar to `liftTermElabM`, but it elaborates all scoped variables declared using the `variable`
729
+ command.
730
+
731
+ Example:
732
+ ```
733
+ import Lean
734
+
735
+ open Lean Elab Command Meta
736
+
737
+ variable {Ξ± : Type u} {f : Ξ± β†’ Ξ±}
738
+ variable (n : Nat)
739
+
740
+ #eval
741
+ runTermElabM fun xs => do
742
+ for x in xs do
743
+ IO.println s!"{← ppExpr x} : {← ppExpr (← inferType x)}"
744
+ ```
745
+ -/
746
+ def runTermElabM (elabFn : Array Expr β†’ TermElabM Ξ±) : CommandElabM Ξ± := do
747
+ let scope ← getScope
748
+ liftTermElabM <|
749
+ Term.withAutoBoundImplicit <|
750
+ Term.elabBinders scope.varDecls fun xs => do
751
+ -- We need to synthesize postponed terms because this is a checkpoint for the auto-bound implicit feature
752
+ -- If we don't use this checkpoint here, then auto-bound implicits in the postponed terms will not be handled correctly.
753
+ Term.synthesizeSyntheticMVarsNoPostponing
754
+ let mut sectionFVars := {}
755
+ for uid in scope.varUIds, x in xs do
756
+ sectionFVars := sectionFVars.insert uid x
757
+ withReader ({ Β· with sectionFVars := sectionFVars }) do
758
+ -- We don't want to store messages produced when elaborating `(getVarDecls s)` because they have already been saved when we elaborated the `variable`(s) command.
759
+ -- So, we use `Core.resetMessageLog`.
760
+ Core.resetMessageLog
761
+ let xs ← Term.addAutoBoundImplicits xs none
762
+ if xs.all (Β·.isFVar) then
763
+ Term.withoutAutoBoundImplicit <| elabFn xs
764
+ else
765
+ -- Abstract any mvars that appear in `xs` using `mkForallFVars` (the type `mkSort levelZero` is an arbitrary placeholder)
766
+ -- and then rebuild the local context from scratch.
767
+ -- Resetting prevents the local context from including the original fvars from `xs`.
768
+ let ctxType ← Meta.mkForallFVars' xs (mkSort levelZero)
769
+ Meta.withLCtx {} {} <| Meta.forallBoundedTelescope ctxType xs.size fun xs _ =>
770
+ Term.withoutAutoBoundImplicit <| elabFn xs
771
+
772
+ private def liftAttrM {Ξ±} (x : AttrM Ξ±) : CommandElabM Ξ± := do
773
+ liftCoreM x
774
+
775
+ /--
776
+ Return the stack of all currently active scopes:
777
+ the base scope always comes last; new scopes are prepended in the front.
778
+ In particular, the current scope is always the first element.
779
+ -/
780
+ def getScopes : CommandElabM (List Scope) := do
781
+ pure (← get).scopes
782
+
783
+ def modifyScope (f : Scope β†’ Scope) : CommandElabM Unit :=
784
+ modify fun s => { s with
785
+ scopes := match s.scopes with
786
+ | h::t => f h :: t
787
+ | [] => unreachable!
788
+ }
789
+
790
+ def withScope (f : Scope β†’ Scope) (x : CommandElabM Ξ±) : CommandElabM Ξ± := do
791
+ match (← get).scopes with
792
+ | [] => x
793
+ | h :: t =>
794
+ try
795
+ modify fun s => { s with scopes := f h :: t }
796
+ x
797
+ finally
798
+ modify fun s => { s with scopes := h :: t }
799
+
800
+ def getLevelNames : CommandElabM (List Name) :=
801
+ return (← getScope).levelNames
802
+
803
+ def addUnivLevel (idStx : Syntax) : CommandElabM Unit := withRef idStx do
804
+ let id := idStx.getId
805
+ let levelNames ← getLevelNames
806
+ if levelNames.elem id then
807
+ throwAlreadyDeclaredUniverseLevel id
808
+ else
809
+ modifyScope fun scope => { scope with levelNames := id :: scope.levelNames }
810
+
811
+ end Elab.Command
812
+
813
+ open Elab Command MonadRecDepth
814
+
815
+ private def liftCommandElabMCore (cmd : CommandElabM Ξ±) (throwOnError : Bool) : CoreM Ξ± := do
816
+ let s : Core.State ← get
817
+ let ctx : Core.Context ← read
818
+ let (a, commandState) ←
819
+ cmd.run {
820
+ fileName := ctx.fileName
821
+ fileMap := ctx.fileMap
822
+ currRecDepth := ctx.currRecDepth
823
+ currMacroScope := ctx.currMacroScope
824
+ ref := ctx.ref
825
+ snap? := none
826
+ cancelTk? := ctx.cancelTk?
827
+ suppressElabErrors := ctx.suppressElabErrors
828
+ } |>.run {
829
+ env := s.env
830
+ nextMacroScope := s.nextMacroScope
831
+ maxRecDepth := ctx.maxRecDepth
832
+ ngen := s.ngen
833
+ auxDeclNGen := s.auxDeclNGen
834
+ scopes := [{ header := "", opts := ctx.options }]
835
+ infoState.enabled := s.infoState.enabled
836
+ }
837
+ modify fun coreState => { coreState with
838
+ env := commandState.env
839
+ nextMacroScope := commandState.nextMacroScope
840
+ ngen := commandState.ngen
841
+ auxDeclNGen := commandState.auxDeclNGen
842
+ traceState.traces := coreState.traceState.traces ++ commandState.traceState.traces
843
+ }
844
+ if throwOnError then
845
+ if let some err := commandState.messages.toArray.find? (Β·.severity matches .error) then
846
+ throwError err.data
847
+ modify fun coreState => { coreState with
848
+ infoState.trees := coreState.infoState.trees.append commandState.infoState.trees
849
+ messages := coreState.messages ++ commandState.messages
850
+ }
851
+ return a
852
+
853
+ /--
854
+ Lifts an action in `CommandElabM` into `CoreM`, updating the environment,
855
+ messages, info trees, traces, the name generator, and macro scopes.
856
+ The action is run in a context with an empty message log, empty trace state, and empty info trees.
857
+
858
+ If `throwOnError` is true, then if the command produces an error message, it is converted into an exception.
859
+ In this case, info trees and messages are not carried over.
860
+
861
+ Commands that modify the processing of subsequent commands,
862
+ such as `open` and `namespace` commands,
863
+ only have an effect for the remainder of the `CommandElabM` computation passed here,
864
+ and do not affect subsequent commands.
865
+
866
+ *Warning:* when using this from `MetaM` monads, the caches are *not* reset.
867
+ If the command defines new instances for example, you should use `Lean.Meta.resetSynthInstanceCache`
868
+ to reset the instance cache.
869
+ While the `modifyEnv` function for `MetaM` clears its caches entirely,
870
+ `liftCommandElabM` has no way to reset these caches.
871
+ -/
872
+ def liftCommandElabM (cmd : CommandElabM Ξ±) (throwOnError : Bool := true) : CoreM Ξ± := do
873
+ -- `observing` ensures that if `cmd` throws an exception we still thread state back to `CoreM`.
874
+ MonadExcept.ofExcept (← liftCommandElabMCore (observing cmd) throwOnError)
875
+
876
+ /--
877
+ Given a command elaborator `cmd`, returns a new command elaborator that
878
+ first evaluates any local `set_option ... in ...` clauses and then invokes `cmd` on what remains.
879
+ -/
880
+ partial def withSetOptionIn (cmd : CommandElab) : CommandElab := fun stx => do
881
+ if stx.getKind == ``Lean.Parser.Command.in &&
882
+ stx[0].getKind == ``Lean.Parser.Command.set_option then
883
+ let opts ← Elab.elabSetOption stx[0][1] stx[0][3]
884
+ Command.withScope (fun scope => { scope with opts }) do
885
+ withSetOptionIn cmd stx[2]
886
+ else
887
+ cmd stx
888
+
889
+ export Elab.Command (Linter addLinter)
890
+
891
+ end Lean
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/ComputedFields.lean ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2022 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Gabriel Ebner
5
+ -/
6
+ prelude
7
+ import Lean.Meta.Constructions.CasesOn
8
+ import Lean.Compiler.ImplementedByAttr
9
+ import Lean.Elab.PreDefinition.WF.Eqns
10
+
11
+ /-!
12
+ # Computed fields
13
+
14
+ Inductives can have computed fields which are recursive functions whose value
15
+ is stored in the constructors, and can be accessed in constant time.
16
+
17
+ ```lean
18
+ inductive Exp
19
+ | hole
20
+ | app (x y : Exp)
21
+ with
22
+ f : Exp β†’ Nat
23
+ | .hole => 42
24
+ | .app x y => f x + f y
25
+
26
+ -- `Exp.f x` runs in constant time, even if `x` is a dag-like value
27
+ ```
28
+
29
+ This file implements the computed fields feature by simulating it via
30
+ `implemented_by`. The main function is `setComputedFields`.
31
+ -/
32
+
33
+ namespace Lean.Elab.ComputedFields
34
+ open Meta
35
+
36
+ /--
37
+ Marks a function as a computed field of an inductive.
38
+
39
+ Computed fields are specified in the with-block of an inductive type declaration. They can be used
40
+ to allow certain values to be computed only once at the time of construction and then later be
41
+ accessed immediately.
42
+
43
+ Example:
44
+ ```
45
+ inductive NatList where
46
+ | nil
47
+ | cons : Nat β†’ NatList β†’ NatList
48
+ with
49
+ @[computed_field] sum : NatList β†’ Nat
50
+ | .nil => 0
51
+ | .cons x l => x + l.sum
52
+ @[computed_field] length : NatList β†’ Nat
53
+ | .nil => 0
54
+ | .cons _ l => l.length + 1
55
+ ```
56
+ -/
57
+ @[builtin_doc]
58
+ builtin_initialize computedFieldAttr : TagAttribute ←
59
+ registerTagAttribute `computed_field "Marks a function as a computed field of an inductive" fun _ => do
60
+ unless (← getOptions).getBool `elaboratingComputedFields do
61
+ throwError "The @[computed_field] attribute can only be used in the with-block of an inductive"
62
+
63
+ def mkUnsafeCastTo (expectedType : Expr) (e : Expr) : MetaM Expr :=
64
+ mkAppOptM ``unsafeCast #[none, expectedType, e]
65
+
66
+ def isScalarField (ctor : Name) : CoreM Bool :=
67
+ return (← getConstInfoCtor ctor).numFields == 0 -- TODO
68
+
69
+ structure Context extends InductiveVal where
70
+ lparams : List Level
71
+ params : Array Expr
72
+ compFields : Array Name
73
+ compFieldVars : Array Expr
74
+ indices : Array Expr
75
+ val : Expr
76
+
77
+ abbrev M := ReaderT Context MetaM
78
+
79
+ -- TODO: doesn't work if match contains patterns like `.app (.app a b) c`
80
+ def getComputedFieldValue (computedField : Name) (ctorTerm : Expr) : MetaM Expr := do
81
+ let ctorName := ctorTerm.getAppFn.constName!
82
+ let ind ← getConstInfoInduct (← getConstInfoCtor ctorName).induct
83
+ let val ← mkAppOptM computedField (.replicate (ind.numParams+ind.numIndices) none ++ #[some ctorTerm])
84
+ let val ←
85
+ if let some wfEqn := WF.eqnInfoExt.find? (← getEnv) computedField then
86
+ pure <| mkAppN (wfEqn.value.instantiateLevelParams wfEqn.levelParams val.getAppFn.constLevels!) val.getAppArgs
87
+ else
88
+ unfoldDefinition val
89
+ let val ← whnfHeadPred val (return ctorTerm.occurs Β·)
90
+ if !ctorTerm.occurs val then return val
91
+ throwError "computed field {computedField} does not reduce for constructor {ctorName}"
92
+
93
+ def validateComputedFields : M Unit := do
94
+ let {compFieldVars, indices, val ..} ← read
95
+ for cf in compFieldVars do
96
+ let ty ← inferType cf
97
+ if ty.containsFVar val.fvarId! then
98
+ throwError "computed field {cf}'s type must not depend on value{indentExpr ty}"
99
+ if indices.any (ty.containsFVar Β·.fvarId!) then
100
+ throwError "computed field {cf}'s type must not depend on indices{indentExpr ty}"
101
+
102
+ def mkImplType : M Unit := do
103
+ let {name, isUnsafe, type, ctors, levelParams, numParams, lparams, params, compFieldVars, ..} ← read
104
+ addDecl <| .inductDecl levelParams numParams
105
+ (isUnsafe := isUnsafe) -- Note: inlining is disabled with unsafe inductives
106
+ [{ name := name ++ `_impl, type,
107
+ ctors := ← ctors.mapM fun ctor => do
108
+ forallTelescope (← inferType (mkAppN (mkConst ctor lparams) params)) fun fields retTy => do
109
+ let retTy := mkAppN (mkConst (name ++ `_impl) lparams) retTy.getAppArgs
110
+ let type ← mkForallFVars (params ++ (if ← isScalarField ctor then #[] else compFieldVars) ++ fields) retTy
111
+ return { name := ctor ++ `_impl, type } }]
112
+
113
+ def overrideCasesOn : M Unit := do
114
+ let {name, numIndices, ctors, lparams, params, compFieldVars, ..} ← read
115
+ let casesOn ← getConstInfoDefn (mkCasesOnName name)
116
+ mkCasesOn (name ++ `_impl)
117
+ let value ←
118
+ forallTelescope (← instantiateForall casesOn.type params) fun xs constMotive => do
119
+ let (indices, major, minors) := (xs[1...=numIndices].toArray,
120
+ xs[numIndices+1]!, xs[(numIndices+2)...*].toArray)
121
+ let majorImplTy := mkAppN (mkConst (name ++ `_impl) lparams) (params ++ indices)
122
+ mkLambdaFVars (params ++ xs) <|
123
+ mkAppN (mkConst (mkCasesOnName (name ++ `_impl))
124
+ (casesOn.levelParams.map mkLevelParam)) <|
125
+ params ++
126
+ #[← withLocalDeclD `a majorImplTy fun majorImpl => do
127
+ withLetDecl `m (← inferType constMotive) constMotive fun m => do
128
+ mkLambdaFVars (#[m] ++ indices ++ #[majorImpl]) m] ++
129
+ indices ++ #[← mkUnsafeCastTo majorImplTy major] ++
130
+ (← (minors.zip ctors.toArray).mapM fun (minor, ctor) => do
131
+ forallTelescope (← inferType minor) fun args _ => do
132
+ mkLambdaFVars ((if ← isScalarField ctor then #[] else compFieldVars) ++ args)
133
+ (← mkUnsafeCastTo constMotive (mkAppN minor args)))
134
+ let nameOverride := mkCasesOnName name ++ `_override
135
+ addDecl <| .defnDecl { casesOn with
136
+ name := nameOverride
137
+ all := [nameOverride]
138
+ value
139
+ hints := .opaque
140
+ safety := .unsafe
141
+ }
142
+ setInlineAttribute (mkCasesOnName name ++ `_override)
143
+ setImplementedBy (mkCasesOnName name) (mkCasesOnName name ++ `_override)
144
+
145
+ def overrideConstructors : M Unit := do
146
+ let {ctors, levelParams, lparams, params, compFields, ..} ← read
147
+ for ctor in ctors do
148
+ forallTelescope (← inferType (mkAppN (mkConst ctor lparams) params)) fun fields retTy => do
149
+ let ctorTerm := mkAppN (mkConst ctor lparams) (params ++ fields)
150
+ let computedFieldVals ←
151
+ -- elaborating a non-exposed def body
152
+ withoutExporting do
153
+ if ← isScalarField ctor then pure #[] else
154
+ compFields.mapM (getComputedFieldValue Β· ctorTerm)
155
+ addDecl <| .defnDecl {
156
+ name := ctor ++ `_override
157
+ levelParams
158
+ type := ← inferType (mkConst ctor lparams)
159
+ value := ← mkLambdaFVars (params ++ fields) <| ← mkUnsafeCastTo retTy <|
160
+ mkAppN (mkConst (ctor ++ `_impl) lparams) (params ++ computedFieldVals ++ fields)
161
+ hints := .opaque
162
+ safety := .unsafe
163
+ }
164
+ setImplementedBy ctor (ctor ++ `_override)
165
+ if ← isScalarField ctor then setInlineAttribute (ctor ++ `_override)
166
+
167
+ def overrideComputedFields : M Unit := do
168
+ let {name, levelParams, ctors, compFields, compFieldVars, lparams, params, indices, val ..} ← read
169
+ withLocalDeclD `x (mkAppN (mkConst (name ++ `_impl) lparams) (params ++ indices)) fun xImpl => do
170
+ for cfn in compFields, cf in compFieldVars do
171
+ if isExtern (← getEnv) cfn then
172
+ compileDecls [cfn]
173
+ continue
174
+ let cases ←
175
+ -- elaborating a non-exposed def body
176
+ withoutExporting do
177
+ ctors.toArray.mapM fun ctor => do
178
+ forallTelescope (← inferType (mkAppN (mkConst ctor lparams) params)) fun fields _ => do
179
+ if ← isScalarField ctor then
180
+ mkLambdaFVars fields <|
181
+ ← getComputedFieldValue cfn (mkAppN (mkConst ctor lparams) (params ++ fields))
182
+ else
183
+ mkLambdaFVars (compFieldVars ++ fields) cf
184
+ addDecl <| .defnDecl {
185
+ name := cfn ++ `_override
186
+ levelParams
187
+ type := ← mkForallFVars (params ++ indices ++ #[val]) (← inferType cf)
188
+ value := ← mkLambdaFVars (params ++ indices ++ #[val]) <|
189
+ ← mkAppOptM (mkCasesOnName (name ++ `_impl))
190
+ ((params ++ #[← mkLambdaFVars (indices.push xImpl) (← inferType cf)] ++ indices ++
191
+ #[← mkUnsafeCastTo (← inferType xImpl) val] ++ cases).map some)
192
+ safety := .unsafe
193
+ hints := .opaque
194
+ }
195
+ setImplementedBy cfn (cfn ++ `_override)
196
+
197
+ def mkComputedFieldOverrides (declName : Name) (compFields : Array Name) : MetaM Unit := do
198
+ let ind ← getConstInfoInduct declName
199
+ if ind.ctors.length < 2 then
200
+ throwError "computed fields require at least two constructors"
201
+ let lparams := ind.levelParams.map mkLevelParam
202
+ forallTelescope ind.type fun paramsIndices _ => do
203
+ withLocalDeclD `x (mkAppN (mkConst ind.name lparams) paramsIndices) fun val => do
204
+ let params := paramsIndices[*...ind.numParams].toArray
205
+ let indices := paramsIndices[ind.numParams...*].toArray
206
+ let compFieldVars := compFields.map fun fieldDeclName =>
207
+ (fieldDeclName.updatePrefix .anonymous,
208
+ fun _ => do inferType (← mkAppM fieldDeclName (params ++ indices ++ #[val])))
209
+ withLocalDeclsD compFieldVars fun compFieldVars => do
210
+ let ctx := { ind with lparams, params, compFields, compFieldVars, indices, val }
211
+ ReaderT.run (r := ctx) do
212
+ validateComputedFields
213
+ mkImplType
214
+ overrideCasesOn
215
+ overrideConstructors
216
+ overrideComputedFields
217
+
218
+ /--
219
+ Sets the computed fields for a block of mutual inductives,
220
+ adding the implementation via `implemented_by`.
221
+
222
+ The `computedFields` argument contains a pair
223
+ for every inductive in the mutual block,
224
+ consisting of the name of the inductive
225
+ and the names of the associated computed fields.
226
+ -/
227
+ def setComputedFields (computedFields : Array (Name Γ— Array Name)) : MetaM Unit := do
228
+ for (indName, computedFieldNames) in computedFields do
229
+ for computedFieldName in computedFieldNames do
230
+ unless computedFieldAttr.hasTag (← getEnv) computedFieldName do
231
+ logError m!"'{computedFieldName}' must be tagged with @[computed_field]"
232
+ mkComputedFieldOverrides indName computedFieldNames
233
+
234
+ -- Once all the implemented_by infrastructure is set up, compile everything.
235
+ compileDecls <| computedFields.toList.map fun (indName, _) =>
236
+ mkCasesOnName indName ++ `_override
237
+
238
+ let mut toCompile := #[]
239
+ for (declName, computedFields) in computedFields do
240
+ let ind ← getConstInfoInduct declName
241
+ for ctor in ind.ctors do
242
+ toCompile := toCompile.push (ctor ++ `_override)
243
+ for fieldName in computedFields do
244
+ unless isExtern (← getEnv) fieldName do
245
+ toCompile := toCompile.push <| fieldName ++ `_override
246
+ compileDecls toCompile.toList
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Config.lean ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Meta.Basic
8
+
9
+ namespace Lean.Elab.Term
10
+
11
+ /--
12
+ Set `isDefEq` configuration for the elaborator.
13
+ Note that we enable all approximations but `quasiPatternApprox`
14
+
15
+ In Lean3 and Lean 4, we used to use the quasi-pattern approximation during elaboration.
16
+ The example:
17
+ ```
18
+ def ex : StateT Ξ΄ (StateT Οƒ Id) Οƒ :=
19
+ monadLift (get : StateT Οƒ Id Οƒ)
20
+ ```
21
+ demonstrates why it produces counterintuitive behavior.
22
+ We have the `Monad-lift` application:
23
+ ```
24
+ @monadLift ?m ?n ?c ?Ξ± (get : StateT Οƒ id Οƒ) : ?n ?Ξ±
25
+ ```
26
+ It produces the following unification problem when we process the expected type:
27
+ ```
28
+ ?n ?Ξ± =?= StateT Ξ΄ (StateT Οƒ id) Οƒ
29
+ ==> (approximate using first-order unification)
30
+ ?n := StateT Ξ΄ (StateT Οƒ id)
31
+ ?Ξ± := Οƒ
32
+ ```
33
+ Then, we need to solve:
34
+ ```
35
+ ?m ?Ξ± =?= StateT Οƒ id Οƒ
36
+ ==> instantiate metavars
37
+ ?m Οƒ =?= StateT Οƒ id Οƒ
38
+ ==> (approximate since it is a quasi-pattern unification constraint)
39
+ ?m := fun Οƒ => StateT Οƒ id Οƒ
40
+ ```
41
+ Note that the constraint is not a Milner pattern because Οƒ is in
42
+ the local context of `?m`. We are ignoring the other possible solutions:
43
+ ```
44
+ ?m := fun Οƒ' => StateT Οƒ id Οƒ
45
+ ?m := fun Οƒ' => StateT Οƒ' id Οƒ
46
+ ?m := fun Οƒ' => StateT Οƒ id Οƒ'
47
+ ```
48
+
49
+ We need the quasi-pattern approximation for elaborating recursor-like expressions (e.g., dependent `match with` expressions).
50
+
51
+ If we had use first-order unification, then we would have produced
52
+ the right answer: `?m := StateT Οƒ id`
53
+
54
+ Haskell would work on this example since it always uses
55
+ first-order unification.
56
+ -/
57
+ def setElabConfig (cfg : Meta.Config) : Meta.Config :=
58
+ { cfg with foApprox := true, ctxApprox := true, constApprox := false, quasiPatternApprox := false }
59
+
60
+
61
+ end Lean.Elab.Term
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/DeclModifiers.lean ADDED
@@ -0,0 +1,306 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2020 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Sebastian Ullrich
5
+ -/
6
+ prelude
7
+ import Lean.Structure
8
+ import Lean.Elab.Attributes
9
+ import Lean.DocString.Add
10
+
11
+ namespace Lean.Elab
12
+
13
+ /--
14
+ Ensure the environment does not contain a declaration with name `declName`.
15
+ Recall that a private declaration cannot shadow a non-private one and vice-versa, although
16
+ they internally have different names.
17
+ -/
18
+ def checkNotAlreadyDeclared {m} [Monad m] [MonadEnv m] [MonadError m] [MonadInfoTree m] (declName : Name) : m Unit := do
19
+ let env ← getEnv
20
+ let addInfo declName := do
21
+ pushInfoLeaf <| .ofTermInfo {
22
+ elaborator := .anonymous, lctx := {}, expectedType? := none
23
+ stx := (← getRef)
24
+ expr := (← mkConstWithLevelParams declName)
25
+ }
26
+ if env.contains declName then
27
+ addInfo declName
28
+ match privateToUserName? declName with
29
+ | none => throwError "'{.ofConstName declName true}' has already been declared"
30
+ | some declName => throwError "private declaration '{.ofConstName declName true}' has already been declared"
31
+ if isReservedName env (privateToUserName declName) || isReservedName env (mkPrivateName (← getEnv) declName) then
32
+ throwError "'{declName}' is a reserved name"
33
+ if env.contains (mkPrivateName env declName) then
34
+ addInfo (mkPrivateName env declName)
35
+ throwError "a private declaration '{.ofConstName declName true}' has already been declared"
36
+ match privateToUserName? declName with
37
+ | none => pure ()
38
+ | some declName =>
39
+ if env.contains declName then
40
+ addInfo declName
41
+ throwError "a non-private declaration '{.ofConstName declName true}' has already been declared"
42
+
43
+ /-- Declaration visibility modifier. That is, whether a declaration is regular, protected or private. -/
44
+ inductive Visibility where
45
+ | regular | Β«protectedΒ» | Β«privateΒ» | Β«publicΒ»
46
+ deriving Inhabited
47
+
48
+ instance : ToString Visibility where
49
+ toString
50
+ | .regular => "regular"
51
+ | .private => "private"
52
+ | .protected => "protected"
53
+ | .public => "public"
54
+
55
+ def Visibility.isPrivate : Visibility β†’ Bool
56
+ | .private => true
57
+ | _ => false
58
+
59
+ def Visibility.isProtected : Visibility β†’ Bool
60
+ | .protected => true
61
+ | _ => false
62
+
63
+ def Visibility.isPublic : Visibility β†’ Bool
64
+ | .public => true
65
+ | _ => false
66
+
67
+ def Visibility.isInferredPublic (env : Environment) (v : Visibility) : Bool :=
68
+ if env.isExporting || !env.header.isModule then !v.isPrivate else v.isPublic
69
+
70
+ /-- Whether a declaration is default, partial or nonrec. -/
71
+ inductive RecKind where
72
+ | Β«partialΒ» | Β«nonrecΒ» | default
73
+ deriving Inhabited
74
+
75
+ /-- Codegen-relevant modifiers. -/
76
+ inductive ComputeKind where
77
+ | regular | Β«metaΒ» | Β«noncomputableΒ»
78
+ deriving Inhabited
79
+
80
+ /-- Flags and data added to declarations (eg docstrings, attributes, `private`, `unsafe`, `partial`, ...). -/
81
+ structure Modifiers where
82
+ /-- Input syntax, used for adjusting declaration range (unless missing) -/
83
+ stx : TSyntax ``Parser.Command.declModifiers := ⟨.missing⟩
84
+ docString? : Option (TSyntax ``Parser.Command.docComment) := none
85
+ visibility : Visibility := Visibility.regular
86
+ computeKind : ComputeKind := .regular
87
+ recKind : RecKind := RecKind.default
88
+ isUnsafe : Bool := false
89
+ attrs : Array Attribute := #[]
90
+ deriving Inhabited
91
+
92
+ def Modifiers.isPrivate (m : Modifiers) : Bool := m.visibility.isPrivate
93
+ def Modifiers.isProtected (m : Modifiers) : Bool := m.visibility.isProtected
94
+ def Modifiers.isPublic (m : Modifiers) : Bool := m.visibility.isPublic
95
+ def Modifiers.isInferredPublic (env : Environment) (m : Modifiers) : Bool :=
96
+ m.visibility.isInferredPublic env
97
+
98
+ def Modifiers.isPartial : Modifiers β†’ Bool
99
+ | { recKind := .partial, .. } => true
100
+ | _ => false
101
+
102
+ /--
103
+ Whether the declaration is explicitly `partial` or should be considered as such via `meta`. In the
104
+ latter case, elaborators should not produce an error if partialty is unnecessary.
105
+ -/
106
+ def Modifiers.isInferredPartial : Modifiers β†’ Bool
107
+ | { recKind := .partial, .. } => true
108
+ | { computeKind := .meta, .. } => true
109
+ | _ => false
110
+
111
+ def Modifiers.isNonrec : Modifiers β†’ Bool
112
+ | { recKind := .nonrec, .. } => true
113
+ | _ => false
114
+
115
+ def Modifiers.isMeta (m : Modifiers) : Bool :=
116
+ m.computeKind matches .meta
117
+
118
+ def Modifiers.isNoncomputable (m : Modifiers) : Bool :=
119
+ m.computeKind matches .noncomputable
120
+
121
+ /-- Adds attribute `attr` in `modifiers` -/
122
+ def Modifiers.addAttr (modifiers : Modifiers) (attr : Attribute) : Modifiers :=
123
+ { modifiers with attrs := modifiers.attrs.push attr }
124
+
125
+ /-- Adds attribute `attr` in `modifiers`, at the beginning -/
126
+ def Modifiers.addFirstAttr (modifiers : Modifiers) (attr : Attribute) : Modifiers :=
127
+ { modifiers with attrs := #[attr] ++ modifiers.attrs }
128
+
129
+ /-- Filters attributes using `p` -/
130
+ def Modifiers.filterAttrs (modifiers : Modifiers) (p : Attribute β†’ Bool) : Modifiers :=
131
+ { modifiers with attrs := modifiers.attrs.filter p }
132
+
133
+ instance : ToFormat Modifiers := ⟨fun m =>
134
+ let components : List Format :=
135
+ (match m.docString? with
136
+ | some str => [f!"/--{str}-/"]
137
+ | none => [])
138
+ ++ (match m.visibility with
139
+ | .regular => []
140
+ | .private => [f!"private"]
141
+ | .protected => [f!"protected"]
142
+ | .public => [f!"public"])
143
+ ++ (match m.computeKind with | .regular => [] | .meta => [f!"meta"] | .noncomputable => [f!"noncomputable"])
144
+ ++ (match m.recKind with | RecKind.partial => [f!"partial"] | RecKind.nonrec => [f!"nonrec"] | _ => [])
145
+ ++ (if m.isUnsafe then [f!"unsafe"] else [])
146
+ ++ m.attrs.toList.map (fun attr => format attr)
147
+ Format.bracket "{" (Format.joinSep components ("," ++ Format.line)) "}"⟩
148
+
149
+ instance : ToString Modifiers := ⟨toString ∘ format⟩
150
+
151
+ /--
152
+ Retrieve doc string from `stx` of the form `(docComment)?`.
153
+ -/
154
+ def expandOptDocComment? [Monad m] [MonadError m] (optDocComment : Syntax) : m (Option String) :=
155
+ match optDocComment.getOptional? with
156
+ | none => return none
157
+ | some s => match s[1] with
158
+ | .atom _ val => return some (val.extract 0 (val.endPos - ⟨2⟩))
159
+ | _ => throwErrorAt s "unexpected doc string{indentD s[1]}"
160
+
161
+ section Methods
162
+
163
+ 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]
164
+
165
+ /-- Elaborate declaration modifiers (i.e., attributes, `partial`, `private`, `protected`, `unsafe`, `meta`, `noncomputable`, doc string)-/
166
+ def elabModifiers (stx : TSyntax ``Parser.Command.declModifiers) : m Modifiers := do
167
+ let docCommentStx := stx.raw[0]
168
+ let attrsStx := stx.raw[1]
169
+ let visibilityStx := stx.raw[2]
170
+ let computeKind :=
171
+ if stx.raw[3].isNone then
172
+ .regular
173
+ else if stx.raw[3][0].getKind == ``Parser.Command.meta then
174
+ .meta
175
+ else
176
+ .noncomputable
177
+ let unsafeStx := stx.raw[4]
178
+ let recKind :=
179
+ if stx.raw[5].isNone then
180
+ RecKind.default
181
+ else if stx.raw[5][0].getKind == ``Parser.Command.partial then
182
+ RecKind.partial
183
+ else
184
+ RecKind.nonrec
185
+ let docString? := docCommentStx.getOptional?.map TSyntax.mk
186
+ let visibility ← match visibilityStx.getOptional? with
187
+ | none => pure .regular
188
+ | some v =>
189
+ match v with
190
+ | `(Parser.Command.visibility| private) => pure .private
191
+ | `(Parser.Command.visibility| protected) => pure .protected
192
+ | `(Parser.Command.visibility| public) => pure .public
193
+ | _ => throwErrorAt v "unexpected visibility modifier"
194
+ let attrs ← match attrsStx.getOptional? with
195
+ | none => pure #[]
196
+ | some attrs => elabDeclAttrs attrs
197
+ return {
198
+ stx, docString?, visibility, computeKind, recKind, attrs,
199
+ isUnsafe := !unsafeStx.isNone
200
+ }
201
+
202
+ /--
203
+ Ensure the function has not already been declared, and apply the given visibility setting to `declName`.
204
+ If `private`, return the updated name using our internal encoding for private names.
205
+ If `protected`, register `declName` as protected in the environment.
206
+ -/
207
+ def applyVisibility (visibility : Visibility) (declName : Name) : m Name := do
208
+ let mut declName := declName
209
+ if !visibility.isInferredPublic (← getEnv) then
210
+ declName := mkPrivateName (← getEnv) declName
211
+ checkNotAlreadyDeclared declName
212
+ if visibility matches .protected then
213
+ modifyEnv fun env => addProtected env declName
214
+ pure declName
215
+
216
+ def checkIfShadowingStructureField (declName : Name) : m Unit := do
217
+ match declName with
218
+ | Name.str pre .. =>
219
+ if isStructure (← getEnv) pre then
220
+ let fieldNames := getStructureFieldsFlattened (← getEnv) pre
221
+ for fieldName in fieldNames do
222
+ if pre ++ fieldName == declName then
223
+ throwError "invalid declaration name '{declName}', structure '{pre}' has field '{fieldName}'"
224
+ | _ => pure ()
225
+
226
+ def mkDeclName (currNamespace : Name) (modifiers : Modifiers) (shortName : Name) : m (Name Γ— Name) := do
227
+ let mut shortName := shortName
228
+ let mut currNamespace := currNamespace
229
+ let view := extractMacroScopes shortName
230
+ let name := view.name
231
+ let isRootName := (`_root_).isPrefixOf name
232
+ if name == `_root_ then
233
+ throwError "invalid declaration name `_root_`, `_root_` is a prefix used to refer to the 'root' namespace"
234
+ let declName := if isRootName then { view with name := name.replacePrefix `_root_ Name.anonymous }.review else currNamespace ++ shortName
235
+ if isRootName then
236
+ let .str p s := name | throwError "invalid declaration name '{name}'"
237
+ shortName := Name.mkSimple s
238
+ currNamespace := p.replacePrefix `_root_ Name.anonymous
239
+ checkIfShadowingStructureField declName
240
+ let declName ← applyVisibility modifiers.visibility declName
241
+ match modifiers.visibility with
242
+ | Visibility.protected =>
243
+ match currNamespace with
244
+ | .str _ s => return (declName, Name.mkSimple s ++ shortName)
245
+ | _ =>
246
+ if shortName.isAtomic then
247
+ throwError "protected declarations must be in a namespace"
248
+ return (declName, shortName)
249
+ | _ => return (declName, shortName)
250
+
251
+ /--
252
+ `declId` is of the form
253
+ ```
254
+ leading_parser ident >> optional (".{" >> sepBy1 ident ", " >> "}")
255
+ ```
256
+ but we also accept a single identifier to users to make macro writing more convenient .
257
+ -/
258
+ def expandDeclIdCore (declId : Syntax) : Name Γ— Syntax :=
259
+ if declId.isIdent then
260
+ (declId.getId, mkNullNode)
261
+ else
262
+ let id := declId[0].getId
263
+ let optUnivDeclStx := declId[1]
264
+ (id, optUnivDeclStx)
265
+
266
+ /-- `expandDeclId` resulting type. -/
267
+ structure ExpandDeclIdResult where
268
+ /-- Short name for recursively referring to the declaration. -/
269
+ shortName : Name
270
+ /-- Fully qualified name that will be used to name the declaration in the kernel. -/
271
+ declName : Name
272
+ /-- Universe parameter names provided using the `universe` command and `.{...}` notation. -/
273
+ levelNames : List Name
274
+
275
+ /--
276
+ Given a declaration identifier (e.g., `ident (".{" ident,+ "}")?`) that may contain explicit universe parameters
277
+ - Ensure the new universe parameters do not shadow universe parameters declared using `universe` command.
278
+ - Create the fully qualified named for the declaration using the current namespace, and given `modifiers`
279
+ - Create a short version for recursively referring to the declaration. Recall that the `protected` modifier affects the generation of the short name.
280
+
281
+ The result also contains the universe parameters provided using `universe` command, and the `.{...}` notation.
282
+
283
+ This commands also stores the doc string stored in `modifiers`.
284
+ -/
285
+ def expandDeclId (currNamespace : Name) (currLevelNames : List Name) (declId : Syntax) (modifiers : Modifiers) : m ExpandDeclIdResult := do
286
+ -- ident >> optional (".{" >> sepBy1 ident ", " >> "}")
287
+ let (shortName, optUnivDeclStx) := expandDeclIdCore declId
288
+ let levelNames ← if optUnivDeclStx.isNone then
289
+ pure currLevelNames
290
+ else
291
+ let extraLevels := optUnivDeclStx[1].getArgs.getEvenElems
292
+ extraLevels.foldlM
293
+ (fun levelNames idStx =>
294
+ let id := idStx.getId
295
+ if levelNames.elem id then
296
+ withRef idStx <| throwAlreadyDeclaredUniverseLevel id
297
+ else
298
+ pure (id :: levelNames))
299
+ currLevelNames
300
+ let (declName, shortName) ← withRef declId <| mkDeclName currNamespace modifiers shortName
301
+ addDocString' declName modifiers.docString?
302
+ return { shortName := shortName, declName := declName, levelNames := levelNames }
303
+
304
+ end Methods
305
+
306
+ end Lean.Elab
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/DeclNameGen.lean ADDED
@@ -0,0 +1,264 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2024 Lean FRO, LLC. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Kyle Miller
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Command
8
+
9
+ /-!
10
+ # Name generator for declarations
11
+
12
+ This module provides functionality to generate a name for a declaration using its binders and its type.
13
+ This is used to generate names for anonymous instances.
14
+
15
+ It uses heuristics to generate an informative but terse name given its namespace, supplied binders, and type.
16
+ It tries to make these relatively unique,
17
+ and it uses suffixes derived from the module to ensure cross-project uniqueness
18
+ when the instance doesn't refer to anything defined in the current project.
19
+
20
+ The name generator can be thought of as a kind of pretty printer, rendering an expression in textual form.
21
+ The general structure of this generator is
22
+ 1. `Lean.Elab.Command.NameGen.winnowExpr` takes an expression and re-uses `Expr` as a data structure
23
+ to record the "Syntax"-like structure.
24
+ 2. `Lean.Elab.Command.NameGen.mkBaseNameCore` formats the result of that as a string.
25
+ It actually does a bit more computation than that, since it further removes duplicate expressions,
26
+ reporting only the first occurrence of each subexpression.
27
+ -/
28
+
29
+ namespace Lean.Elab.Command
30
+
31
+ open Meta
32
+
33
+ namespace NameGen
34
+
35
+ /--
36
+ If `e` is an application of a projection to a parent structure, returns the term being projected.
37
+ -/
38
+ private def getParentProjArg (e : Expr) : MetaM (Option Expr) := do
39
+ let .const c@(.str _ field) _ := e.getAppFn | return none
40
+ let env ← getEnv
41
+ let some info := env.getProjectionFnInfo? c | return none
42
+ unless e.getAppNumArgs == info.numParams + 1 do return none
43
+ let some (.ctorInfo cVal) := env.find? info.ctorName | return none
44
+ if isSubobjectField? env cVal.induct (Name.mkSimple field) |>.isNone then return none
45
+ return e.appArg!
46
+
47
+ /--
48
+ Strips out universes and arguments we decide are unnecessary for naming.
49
+ The resulting expression can have loose fvars and be mangled in other ways.
50
+ Expressions can also be replaced by `.bvar 0` if they shouldn't be mentioned.
51
+ -/
52
+ private partial def winnowExpr (e : Expr) : MetaM Expr := do
53
+ let rec visit (e : Expr) : MonadCacheT Expr Expr MetaM Expr := checkCache e fun _ => do
54
+ if ← isProof e then
55
+ return .bvar 0
56
+ match e with
57
+ | .app .. =>
58
+ if let some e' ← getParentProjArg e then
59
+ return (← visit e')
60
+ e.withApp fun f args => do
61
+ -- Visit only the explicit arguments to `f` and also its type (and type family) arguments.
62
+ -- The reason we visit type arguments is so that, for example, `Decidable (_ < _)` has
63
+ -- a chance to insert type information. Type families are for reporting things such as type constructors and monads.
64
+ let mut fty ← inferType f
65
+ let mut j := 0
66
+ let mut e' ← visit f
67
+ for h : i in [0:args.size] do
68
+ unless fty.isForall do
69
+ fty ← withTransparency .all <| whnf <| fty.instantiateRevRange j i args
70
+ j := i
71
+ let .forallE _ _ fty' bi := fty | failure
72
+ fty := fty'
73
+ let arg := args[i]
74
+ if ← pure bi.isExplicit <||> (pure !arg.isSort <&&> isTypeFormer arg) then
75
+ unless (← isProof arg) do
76
+ e' := .app e' (← visit arg)
77
+ return e'
78
+ | .forallE n ty body bi =>
79
+ withLocalDecl n bi ty fun arg => do
80
+ -- In a dependent forall the body implies `ty`, so we won't mention it.
81
+ let ty' ← if body.hasLooseBVars then pure (.bvar 0) else visit ty
82
+ return .forallE n ty' (← visit (body.instantiate1 arg)) bi
83
+ | .lam n ty body bi =>
84
+ if let some e := Expr.etaExpandedStrict? e then
85
+ visit e
86
+ else
87
+ withLocalDecl n bi ty fun arg => do
88
+ -- Don't record the `.lam` since `ty` should be recorded elsewhere in the expression.
89
+ visit (body.instantiate1 arg)
90
+ | .letE _n _t v b _ => visit (b.instantiate1 v)
91
+ | .sort .. =>
92
+ if e.isProp then return .sort levelZero
93
+ else if e.isType then return .sort levelOne
94
+ else return .sort (.param `u)
95
+ | .const name .. => return .const name []
96
+ | .mdata _ e' => visit e'
97
+ | _ => return .bvar 0
98
+ visit e |>.run
99
+
100
+ /--
101
+ State for name generation.
102
+ -/
103
+ private structure MkNameState where
104
+ /-- Keeps track of expressions already visited so that we do not include them again. -/
105
+ seen : ExprSet := {}
106
+ /-- Keeps track of constants that appear in the generated name. -/
107
+ consts : NameSet := {}
108
+
109
+ /--
110
+ Monad for name generation.
111
+ -/
112
+ private abbrev MkNameM := StateRefT MkNameState MetaM
113
+
114
+ /--
115
+ Core algorithm for generating a name. The provided expression should be a winnowed expression.
116
+
117
+ - `omitTopForall` if true causes "Forall" to not be included if the binding type results in an empty string.
118
+ -/
119
+ private def mkBaseNameCore (e : Expr) (omitTopForall : Bool := false) : MkNameM String :=
120
+ visit e omitTopForall
121
+ where
122
+ visit (e : Expr) (omitTopForall : Bool := false) : MkNameM String := do
123
+ if (← get).seen.contains e then
124
+ return ""
125
+ else
126
+ let s ← visit' e omitTopForall
127
+ modify fun st => {st with seen := st.seen.insert e}
128
+ return s
129
+ visit' (e : Expr) (omitTopForall : Bool) : MkNameM String := do
130
+ match e with
131
+ | .const name .. =>
132
+ modify (fun st => {st with consts := st.consts.insert name})
133
+ return match name.eraseMacroScopes with
134
+ | .str _ str => str.capitalize
135
+ | _ => ""
136
+ | .app f x => (Β· ++ Β·) <$> visit f <*> visit x
137
+ | .forallE _ ty body _ =>
138
+ let sty ← visit ty
139
+ if omitTopForall && sty == "" then
140
+ visit body true
141
+ else
142
+ ("Forall" ++ sty ++ Β·) <$> visit body
143
+ | .sort .zero => return "Prop"
144
+ | .sort (.succ _) => return "Type"
145
+ | .sort _ => return "Sort"
146
+ | _ => return ""
147
+
148
+ /--
149
+ Generate a name, while naming the top-level foralls using "Of".
150
+ The provided expression should be a winnowed expression.
151
+ -/
152
+ private partial def mkBaseNameAux (e : Expr) : MkNameM String := do
153
+ let (foralls, sb) ← visit e
154
+ return sb ++ String.join foralls
155
+ where
156
+ visit (e : Expr) : MkNameM (List String Γ— String) := do
157
+ match e with
158
+ | .forallE _ ty body _ =>
159
+ let (foralls, sb) ← visit body
160
+ let st ← mkBaseNameCore ty (omitTopForall := true)
161
+ if st == "" then
162
+ return (foralls, sb)
163
+ else
164
+ return (("Of" ++ st) :: foralls, sb)
165
+ | _ => return ([], ← mkBaseNameCore e)
166
+
167
+ /--
168
+ Adds all prefixes of `ns` as seen constants.
169
+ -/
170
+ private def visitNamespace (ns : Name) : MkNameM Unit := do
171
+ match ns with
172
+ | .anonymous => pure ()
173
+ | .num ns' _ => visitNamespace ns'
174
+ | .str ns' _ =>
175
+ let env ← getEnv
176
+ if env.contains ns then
177
+ modify fun st => {st with seen := st.seen.insert (.const ns []), consts := st.consts.insert ns}
178
+ visitNamespace ns'
179
+
180
+ /--
181
+ Given an expression, generates a "base name" for a declaration.
182
+ The top-level foralls in `e` are treated as being binders, so use the `...Of...` naming convention.
183
+ The current namespace is used to seed the seen expressions with each prefix of the namespace that's a global constant.
184
+
185
+ Collects all constants that contribute to the name in the `MkInstM` state.
186
+ This can be used to decide whether to further transform the generated name;
187
+ in particular, this enables checking whether the generated name mentions declarations
188
+ from the current module or project.
189
+ -/
190
+ def mkBaseName (e : Expr) : MkNameM String := do
191
+ let e ← instantiateMVars e
192
+ visitNamespace (← getCurrNamespace)
193
+ mkBaseNameAux (← winnowExpr e)
194
+
195
+ /--
196
+ Converts a module name into a suffix. Includes a leading `_`,
197
+ so for example `Lean.Elab.DefView` becomes `_lean_elab_defView`.
198
+ -/
199
+ private def moduleToSuffix : Name β†’ String
200
+ | .anonymous => ""
201
+ | .num n _ => moduleToSuffix n
202
+ | .str n s => moduleToSuffix n ++ "_" ++ s.decapitalize
203
+
204
+ /--
205
+ Uses heuristics to generate an informative but terse base name for a term of the given type, using `mkBaseName`.
206
+ Makes use of the current namespace.
207
+ It tries to make these names relatively unique ecosystem-wide,
208
+ and it adds suffixes using the current module if the resulting name doesn't refer to anything defined in this module.
209
+
210
+ If any constant in `type` has a name with macro scopes, then the result will be a name with fresh macro scopes.
211
+ While in this case we could skip the naming heuristics, we still want informative names for debugging purposes.
212
+ -/
213
+ def mkBaseNameWithSuffix (pre : String) (type : Expr) : MetaM Name := do
214
+ let (name, st) ← mkBaseName type |>.run {}
215
+ let name := pre ++ name
216
+ let project := (← getMainModule).getRoot
217
+ -- Collect the modules for each constant that appeared.
218
+ let modules ← st.consts.foldM (init := Array.mkEmpty st.consts.size) fun mods name => return mods.push (← findModuleOf? name)
219
+ -- We can avoid adding the suffix if the instance refers to module-local names.
220
+ let isModuleLocal := modules.any Option.isNone
221
+ -- We can also avoid adding the full module suffix if the instance refers to "project"-local names.
222
+ let isProjectLocal := isModuleLocal || modules.any fun mod? => mod?.map (Β·.getRoot) == project
223
+ let name := Name.mkSimple <|
224
+ if !isProjectLocal then
225
+ s!"{name}{moduleToSuffix project}"
226
+ else
227
+ name
228
+ if Option.isSome <| type.find? (fun e => if let .const n _ := e then n.hasMacroScopes else false) then
229
+ mkFreshUserName name
230
+ else
231
+ return name
232
+
233
+ /--
234
+ Elaborates the binders and type and then uses `mkBaseNameWithSuffix` to generate a name.
235
+ Furthermore, uses `mkUnusedBaseName` on the result.
236
+ -/
237
+ def mkBaseNameWithSuffix' (pre : String) (binders : Array Syntax) (type : Syntax) : TermElabM Name := do
238
+ let name ←
239
+ try
240
+ Term.withAutoBoundImplicit <| Term.elabBinders binders fun binds => Term.withoutErrToSorry do
241
+ let ty ← mkForallFVars binds (← Term.elabType type)
242
+ mkBaseNameWithSuffix pre ty
243
+ catch _ =>
244
+ mkFreshUserName <| Name.mkSimple pre
245
+ liftMacroM <| mkUnusedBaseName name
246
+
247
+ end NameGen
248
+
249
+ /--
250
+ Generates an instance name for a declaration that has the given binders and type.
251
+ It tries to make these names relatively unique ecosystem-wide.
252
+
253
+ Note that this elaborates the binders and the type.
254
+ This means that when elaborating an instance declaration, we elaborate these twice.
255
+ -/
256
+ def mkInstanceName (binders : Array Syntax) (type : Syntax) : CommandElabM Name := do
257
+ let savedState ← get
258
+ try
259
+ -- Unfortunately we can't include any of the binders from `runTermElabM` since, without
260
+ -- elaborating the body of the instance, we have no idea which of these binders are
261
+ -- actually used.
262
+ runTermElabM fun _ => NameGen.mkBaseNameWithSuffix' "inst" binders type
263
+ finally
264
+ set savedState
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/DeclUtil.lean ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2020 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Sebastian Ullrich
5
+ -/
6
+ prelude
7
+ import Lean.Meta.Basic
8
+ import Lean.Meta.Check
9
+
10
+ namespace Lean.Meta
11
+
12
+ def forallTelescopeCompatibleAux (k : Array Expr β†’ Expr β†’ Expr β†’ MetaM Ξ±) : Nat β†’ Expr β†’ Expr β†’ Array Expr β†’ MetaM Ξ±
13
+ | 0, type₁, typeβ‚‚, xs => k xs type₁ typeβ‚‚
14
+ | i+1, type₁, typeβ‚‚, xs => do
15
+ let type₁ ← whnf type₁
16
+ let typeβ‚‚ ← whnf typeβ‚‚
17
+ match type₁, typeβ‚‚ with
18
+ | .forallE n₁ d₁ b₁ c₁, .forallE nβ‚‚ dβ‚‚ bβ‚‚ cβ‚‚ =>
19
+ -- Remark: we use `mkIdent` to ensure macroscopes do not leak into error messages
20
+ unless c₁ == cβ‚‚ do
21
+ throwError "binder annotation mismatch at parameter '{mkIdent n₁}'"
22
+ /-
23
+ Remark: recall that users may suppress parameter names for instance implicit arguments.
24
+ A fresh name (with macro scopes) is generated in this case. Thus, we allow the names
25
+ to be different in this case. See issue #4310.
26
+ -/
27
+ unless n₁ == nβ‚‚ || (c₁.isInstImplicit && n₁.hasMacroScopes && nβ‚‚.hasMacroScopes) do
28
+ throwError "parameter name mismatch '{mkIdent n₁}', expected '{mkIdent nβ‚‚}'"
29
+ unless (← isDefEq d₁ dβ‚‚) do
30
+ throwError "parameter '{mkIdent n₁}' {← mkHasTypeButIsExpectedMsg d₁ dβ‚‚}"
31
+ withLocalDecl n₁ c₁ d₁ fun x =>
32
+ let type₁ := b₁.instantiate1 x
33
+ let typeβ‚‚ := bβ‚‚.instantiate1 x
34
+ forallTelescopeCompatibleAux k i type₁ typeβ‚‚ (xs.push x)
35
+ | _, _ => throwError "unexpected number of parameters"
36
+
37
+ /-- Given two forall-expressions `type₁` and `typeβ‚‚`, ensure the first `numParams` parameters are compatible, and
38
+ then execute `k` with the parameters and remaining types. -/
39
+ def forallTelescopeCompatible [Monad m] [MonadControlT MetaM m] (type₁ typeβ‚‚ : Expr) (numParams : Nat) (k : Array Expr β†’ Expr β†’ Expr β†’ m Ξ±) : m Ξ± :=
40
+ controlAt MetaM fun runInBase =>
41
+ forallTelescopeCompatibleAux (fun xs type₁ typeβ‚‚ => runInBase $ k xs type₁ typeβ‚‚) numParams type₁ typeβ‚‚ #[]
42
+
43
+ end Meta
44
+
45
+ namespace Elab
46
+
47
+ def expandOptDeclSig (stx : Syntax) : Syntax Γ— Option Syntax :=
48
+ -- many Term.bracketedBinder >> Term.optType
49
+ let binders := stx[0]
50
+ let optType := stx[1] -- optional (leading_parser " : " >> termParser)
51
+ if optType.isNone then
52
+ (binders, none)
53
+ else
54
+ let typeSpec := optType[0]
55
+ (binders, some typeSpec[1])
56
+
57
+ def expandDeclSig (stx : Syntax) : Syntax Γ— Syntax :=
58
+ -- many Term.bracketedBinder >> Term.typeSpec
59
+ let binders := stx[0]
60
+ let typeSpec := stx[1]
61
+ (binders, typeSpec[1])
62
+
63
+ /--
64
+ Sort the given list of `usedParams` using the following order:
65
+ - If it is an explicit level in `allUserParams`, then use user-given order.
66
+ - All other levels come in lexicographic order after these.
67
+
68
+ Remark: `scopeParams` are the universe params introduced using the `universe` command. `allUserParams` contains
69
+ the universe params introduced using the `universe` command *and* the `.{...}` notation.
70
+
71
+ Remark: this function return an exception if there is an `u` not in `usedParams`, that is in `allUserParams` but not in `scopeParams`.
72
+
73
+ Remark: `scopeParams` and `allUserParams` are in reverse declaration order. That is, the head is the last declared parameter.
74
+ -/
75
+ def sortDeclLevelParams (scopeParams : List Name) (allUserParams : List Name) (usedParams : Array Name) : Except String (List Name) :=
76
+ match allUserParams.find? fun u => !usedParams.contains u && !scopeParams.elem u with
77
+ | some u => throw s!"unused universe parameter '{u}'"
78
+ | none =>
79
+ -- Recall that `allUserParams` (like `scopeParams`) are in reverse order. That is, the last declared universe is the first element of the list.
80
+ -- The following `foldl` will reverse the elements and produce a list of universe levels using the user given order.
81
+ let result := allUserParams.foldl (fun result levelName => if usedParams.elem levelName then levelName :: result else result) []
82
+ let remaining := usedParams.filter (fun levelParam => !allUserParams.elem levelParam)
83
+ let remaining := remaining.qsort Name.lt
84
+ return result ++ remaining.toList
85
+
86
+ end Lean.Elab
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Declaration.lean ADDED
@@ -0,0 +1,347 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2020 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Sebastian Ullrich
5
+ -/
6
+ prelude
7
+ import Lean.Util.CollectLevelParams
8
+ import Lean.Elab.DeclUtil
9
+ import Lean.Elab.DefView
10
+ import Lean.Elab.MutualDef
11
+ import Lean.Elab.MutualInductive
12
+ import Lean.Elab.DeclarationRange
13
+ namespace Lean.Elab.Command
14
+
15
+ open Meta
16
+
17
+ private def ensureValidNamespace (name : Name) : MacroM Unit := do
18
+ match name with
19
+ | .str p s =>
20
+ if s == "_root_" then
21
+ Macro.throwError s!"invalid namespace '{name}', '_root_' is a reserved namespace"
22
+ ensureValidNamespace p
23
+ | .num .. => Macro.throwError s!"invalid namespace '{name}', it must not contain numeric parts"
24
+ | .anonymous => return ()
25
+
26
+ private def setDeclIdName (declId : Syntax) (nameNew : Name) : Syntax :=
27
+ let (id, _) := expandDeclIdCore declId
28
+ -- We should not update the name of `def _root_.` declarations
29
+ assert! !(`_root_).isPrefixOf id
30
+ let idStx := mkIdent nameNew |>.raw.setInfo declId.getHeadInfo
31
+ if declId.isIdent then
32
+ idStx
33
+ else
34
+ declId.setArg 0 idStx
35
+
36
+ /-- Return `true` if `stx` is a `Command.declaration`, and it is a definition that always has a name. -/
37
+ private def isNamedDef (stx : Syntax) : Bool :=
38
+ if !stx.isOfKind ``Lean.Parser.Command.declaration then
39
+ false
40
+ else
41
+ let decl := stx[1]
42
+ let k := decl.getKind
43
+ k == ``Lean.Parser.Command.abbrev ||
44
+ k == ``Lean.Parser.Command.definition ||
45
+ k == ``Lean.Parser.Command.theorem ||
46
+ k == ``Lean.Parser.Command.opaque ||
47
+ k == ``Lean.Parser.Command.axiom ||
48
+ k == ``Lean.Parser.Command.inductive ||
49
+ k == ``Lean.Parser.Command.classInductive ||
50
+ k == ``Lean.Parser.Command.structure
51
+
52
+ /-- Return `true` if `stx` is an `instance` declaration command -/
53
+ private def isInstanceDef (stx : Syntax) : Bool :=
54
+ stx.isOfKind ``Lean.Parser.Command.declaration &&
55
+ stx[1].getKind == ``Lean.Parser.Command.instance
56
+
57
+ /-- Return `some name` if `stx` is a definition named `name` -/
58
+ private def getDefName? (stx : Syntax) : Option Name := do
59
+ if isNamedDef stx then
60
+ let (id, _) := expandDeclIdCore stx[1][1]
61
+ some id
62
+ else if isInstanceDef stx then
63
+ let optDeclId := stx[1][3]
64
+ if optDeclId.isNone then none
65
+ else
66
+ let (id, _) := expandDeclIdCore optDeclId[0]
67
+ some id
68
+ else
69
+ none
70
+
71
+ /--
72
+ Update the name of the given definition.
73
+ This function assumes `stx` is not a nameless instance.
74
+ -/
75
+ private def setDefName (stx : Syntax) (name : Name) : Syntax :=
76
+ if isNamedDef stx then
77
+ stx.setArg 1 <| stx[1].setArg 1 <| setDeclIdName stx[1][1] name
78
+ else if isInstanceDef stx then
79
+ -- We never set the name of nameless instance declarations
80
+ assert! !stx[1][3].isNone
81
+ stx.setArg 1 <| stx[1].setArg 3 <| stx[1][3].setArg 0 <| setDeclIdName stx[1][3][0] name
82
+ else
83
+ stx
84
+
85
+ /--
86
+ Given declarations such as `@[...] def Foo.Bla.f ...` return `some (Foo.Bla, @[...] def f ...)`
87
+ Remark: if the id starts with `_root_`, we return `none`.
88
+ -/
89
+ private def expandDeclNamespace? (stx : Syntax) : MacroM (Option (Name Γ— Syntax)) := do
90
+ let some name := getDefName? stx | return none
91
+ if (`_root_).isPrefixOf name then
92
+ ensureValidNamespace (name.replacePrefix `_root_ Name.anonymous)
93
+ return none
94
+ let scpView := extractMacroScopes name
95
+ match scpView.name with
96
+ | .str .anonymous _ => return none
97
+ | .str pre shortName => return some (pre, setDefName stx { scpView with name := .mkSimple shortName }.review)
98
+ | _ => return none
99
+
100
+ def elabAxiom (modifiers : Modifiers) (stx : Syntax) : CommandElabM Unit := do
101
+ -- leading_parser "axiom " >> declId >> declSig
102
+ let declId := stx[1]
103
+ let (binders, typeStx) := expandDeclSig stx[2]
104
+ runTermElabM fun vars => do
105
+ let scopeLevelNames ← Term.getLevelNames
106
+ let ⟨shortName, declName, allUserLevelNames⟩ ← Term.expandDeclId (← getCurrNamespace) scopeLevelNames declId modifiers
107
+ addDeclarationRangesForBuiltin declName modifiers.stx stx
108
+ Term.withAutoBoundImplicit do
109
+ Term.withAutoBoundImplicitForbiddenPred (fun n => shortName == n) do
110
+ Term.withDeclName declName <| Term.withLevelNames allUserLevelNames <| Term.elabBinders binders.getArgs fun xs => do
111
+ Term.applyAttributesAt declName modifiers.attrs AttributeApplicationTime.beforeElaboration
112
+ let type ← Term.elabType typeStx
113
+ Term.synthesizeSyntheticMVarsNoPostponing
114
+ let xs ← Term.addAutoBoundImplicits xs (declId.getTailPos? (canonicalOnly := true))
115
+ let type ← instantiateMVars type
116
+ let type ← mkForallFVars xs type
117
+ let type ← mkForallFVars vars type (usedOnly := true)
118
+ let type ← Term.levelMVarToParam type
119
+ let usedParams := collectLevelParams {} type |>.params
120
+ match sortDeclLevelParams scopeLevelNames allUserLevelNames usedParams with
121
+ | Except.error msg => throwErrorAt stx msg
122
+ | Except.ok levelParams =>
123
+ let type ← instantiateMVars type
124
+ let decl := Declaration.axiomDecl {
125
+ name := declName,
126
+ levelParams := levelParams,
127
+ type := type,
128
+ isUnsafe := modifiers.isUnsafe
129
+ }
130
+ trace[Elab.axiom] "{declName} : {type}"
131
+ Term.ensureNoUnassignedMVars decl
132
+ addDecl decl
133
+ withSaveInfoContext do -- save new env
134
+ Term.addTermInfo' declId (← mkConstWithLevelParams declName) (isBinder := true)
135
+ Term.applyAttributesAt declName modifiers.attrs AttributeApplicationTime.afterTypeChecking
136
+ if isExtern (← getEnv) declName then
137
+ compileDecl decl
138
+ Term.applyAttributesAt declName modifiers.attrs AttributeApplicationTime.afterCompilation
139
+
140
+ /--
141
+ Macro that expands a declaration with a complex name into an explicit `namespace` block.
142
+ Implementing this step as a macro means that reuse checking is handled by `elabCommand`.
143
+ -/
144
+ @[builtin_macro Lean.Parser.Command.declaration]
145
+ def expandNamespacedDeclaration : Macro := fun stx => do
146
+ match (← expandDeclNamespace? stx) with
147
+ | some (ns, newStx) => do
148
+ -- Limit ref variability for incrementality; see Note [Incremental Macros]
149
+ let declTk := stx[1][0]
150
+ let ns := mkIdentFrom declTk ns
151
+ withRef declTk `(namespace $ns $(⟨newStx⟩) end $ns)
152
+ | none => Macro.throwUnsupported
153
+
154
+ @[builtin_command_elab declaration, builtin_incremental]
155
+ def elabDeclaration : CommandElab := fun stx => do
156
+ withExporting (isExporting := (← getScope).isPublic) do
157
+ let modifiers : TSyntax ``Parser.Command.declModifiers := ⟨stx[0]⟩
158
+ let decl := stx[1]
159
+ let declKind := decl.getKind
160
+ if isDefLike decl then
161
+ -- only case implementing incrementality currently
162
+ elabMutualDef #[stx]
163
+ else withoutCommandIncrementality true do
164
+ let modifiers ← elabModifiers modifiers
165
+ withExporting (isExporting := modifiers.isInferredPublic (← getEnv)) do
166
+ if declKind == ``Lean.Parser.Command.Β«axiomΒ» then
167
+ elabAxiom modifiers decl
168
+ else if declKind == ``Lean.Parser.Command.Β«inductiveΒ»
169
+ || declKind == ``Lean.Parser.Command.classInductive
170
+ || declKind == ``Lean.Parser.Command.Β«structureΒ» then
171
+ elabInductive modifiers decl
172
+ else
173
+ throwError "unexpected declaration"
174
+
175
+ /-- Return true if all elements of the mutual-block are definitions/theorems/abbrevs. -/
176
+ private def isMutualDef (stx : Syntax) : Bool :=
177
+ stx[1].getArgs.all fun elem =>
178
+ let decl := elem[1]
179
+ isDefLike decl
180
+
181
+ private def isMutualPreambleCommand (stx : Syntax) : Bool :=
182
+ let k := stx.getKind
183
+ k == ``Lean.Parser.Command.variable ||
184
+ k == ``Lean.Parser.Command.universe ||
185
+ k == ``Lean.Parser.Command.check ||
186
+ k == ``Lean.Parser.Command.set_option ||
187
+ k == ``Lean.Parser.Command.open
188
+
189
+ private partial def splitMutualPreamble (elems : Array Syntax) : Option (Array Syntax Γ— Array Syntax) :=
190
+ let rec loop (i : Nat) : Option (Array Syntax Γ— Array Syntax) :=
191
+ if h : i < elems.size then
192
+ if isMutualPreambleCommand elems[i] then
193
+ loop (i+1)
194
+ else if i == 0 then
195
+ none -- `mutual` block does not contain any preamble commands
196
+ else
197
+ some (elems[*...i], elems[i...elems.size])
198
+ else
199
+ none -- a `mutual` block containing only preamble commands is not a valid `mutual` block
200
+ loop 0
201
+
202
+ /--
203
+ Find the common namespace for the given names.
204
+ Example:
205
+ ```
206
+ findCommonPrefix [`Lean.Elab.eval, `Lean.mkConst, `Lean.Elab.Tactic.evalTactic]
207
+ -- `Lean
208
+ ```
209
+ -/
210
+ def findCommonPrefix (ns : List Name) : Name :=
211
+ match ns with
212
+ | [] => .anonymous
213
+ | n :: ns => go n ns
214
+ where
215
+ go (n : Name) (ns : List Name) : Name :=
216
+ match n with
217
+ | .anonymous => .anonymous
218
+ | _ => match ns with
219
+ | [] => n
220
+ | n' :: ns => go (findCommon n.components n'.components) ns
221
+ findCommon (as bs : List Name) : Name :=
222
+ match as, bs with
223
+ | a :: as, b :: bs => if a == b then a ++ findCommon as bs else .anonymous
224
+ | _, _ => .anonymous
225
+
226
+
227
+ @[builtin_macro Lean.Parser.Command.mutual]
228
+ def expandMutualNamespace : Macro := fun stx => do
229
+ let mut nss := #[]
230
+ for elem in stx[1].getArgs do
231
+ match (← expandDeclNamespace? elem) with
232
+ | none => Macro.throwUnsupported
233
+ | some (n, _) => nss := nss.push n
234
+ let common := findCommonPrefix nss.toList
235
+ if common.isAnonymous then Macro.throwUnsupported
236
+ let elemsNew ← stx[1].getArgs.mapM fun elem => do
237
+ let some name := getDefName? elem | unreachable!
238
+ let view := extractMacroScopes name
239
+ let nameNew := { view with name := view.name.replacePrefix common .anonymous }.review
240
+ return setDefName elem nameNew
241
+ let ns := mkIdentFrom stx common
242
+ let stxNew := stx.setArg 1 (mkNullNode elemsNew)
243
+ `(namespace $ns $(⟨stxNew⟩) end $ns)
244
+
245
+ @[builtin_macro Lean.Parser.Command.mutual]
246
+ def expandMutualElement : Macro := fun stx => do
247
+ let mut elemsNew := #[]
248
+ let mut modified := false
249
+ for elem in stx[1].getArgs do
250
+ -- Don't trigger the `expandNamespacedDecl` macro, the namespace is handled by the mutual def
251
+ -- elaborator directly instead
252
+ if elem.isOfKind ``Parser.Command.declaration then
253
+ continue
254
+ match (← expandMacro? elem) with
255
+ | some elemNew => elemsNew := elemsNew.push elemNew; modified := true
256
+ | none => elemsNew := elemsNew.push elem
257
+ if modified then
258
+ return stx.setArg 1 (mkNullNode elemsNew)
259
+ else
260
+ Macro.throwUnsupported
261
+
262
+ @[builtin_macro Lean.Parser.Command.mutual]
263
+ def expandMutualPreamble : Macro := fun stx =>
264
+ match splitMutualPreamble stx[1].getArgs with
265
+ | none => Macro.throwUnsupported
266
+ | some (preamble, rest) => do
267
+ let secCmd ← `(section)
268
+ let newMutual := stx.setArg 1 (mkNullNode rest)
269
+ let endCmd ← `(end)
270
+ return mkNullNode (#[secCmd] ++ preamble ++ #[newMutual] ++ #[endCmd])
271
+
272
+ @[builtin_command_elab Β«mutualΒ», builtin_incremental]
273
+ def elabMutual : CommandElab := fun stx => do
274
+ withExporting (isExporting := (← getScope).isPublic) do
275
+ if isMutualDef stx then
276
+ -- only case implementing incrementality currently
277
+ elabMutualDef stx[1].getArgs
278
+ else withoutCommandIncrementality true do
279
+ if ← isMutualInductive stx then
280
+ elabMutualInductive stx[1].getArgs
281
+ else
282
+ throwError "invalid mutual block: either all elements of the block must be inductive/structure declarations, or they must all be definitions/theorems/abbrevs"
283
+
284
+ /- leading_parser "attribute " >> "[" >> sepBy1 (eraseAttr <|> Term.attrInstance) ", " >> "]" >> many1 ident -/
285
+ @[builtin_command_elab Β«attributeΒ»] def elabAttr : CommandElab := fun stx => do
286
+ let mut attrInsts := #[]
287
+ let mut toErase := #[]
288
+ for attrKindStx in stx[2].getSepArgs do
289
+ if attrKindStx.getKind == ``Lean.Parser.Command.eraseAttr then
290
+ let attrName := attrKindStx[1].getId.eraseMacroScopes
291
+ if isAttribute (← getEnv) attrName then
292
+ toErase := toErase.push attrName
293
+ else
294
+ logErrorAt attrKindStx m!"unknown attribute [{attrName}]"
295
+ else
296
+ attrInsts := attrInsts.push attrKindStx
297
+ let attrs ← elabAttrs attrInsts
298
+ let idents := stx[4].getArgs
299
+ for ident in idents do withRef ident <| liftTermElabM do
300
+ /-
301
+ HACK to allow `attribute` command to disable builtin simprocs.
302
+ TODO: find a better solution. Example: have some "fake" declaration
303
+ for builtin simprocs.
304
+ -/
305
+ let declNames ←
306
+ try
307
+ realizeGlobalConstWithInfos ident
308
+ catch _ =>
309
+ let name := ident.getId.eraseMacroScopes
310
+ if (← Simp.isBuiltinSimproc name) then
311
+ pure [name]
312
+ else
313
+ throwUnknownConstantAt ident name
314
+ let declName ← ensureNonAmbiguous ident declNames
315
+ Term.applyAttributes declName attrs
316
+ for attrName in toErase do
317
+ Attribute.erase declName attrName
318
+
319
+ @[builtin_command_elab Lean.Parser.Command.Β«initializeΒ»] def elabInitialize : CommandElab
320
+ | stx@`($declModifiers:declModifiers $kw:initializeKeyword $[$id? : $type? ←]? $doSeq) => do
321
+ let attrId := mkIdentFrom stx <| if kw.raw[0].isToken "initialize" then `init else `builtin_init
322
+ if let (some id, some type) := (id?, type?) then
323
+ let `(Parser.Command.declModifiersT| $[$doc?:docComment]? $[@[$attrs?,*]]? $(vis?)? $[unsafe%$unsafe?]?) := stx[0]
324
+ | throwErrorAt declModifiers "invalid initialization command, unexpected modifiers"
325
+ let defStx ← `($[$doc?:docComment]? @[$attrId:ident initFn, $(attrs?.getD βˆ…),*] $(vis?)? opaque $id : $type)
326
+ let mut fullId := (← getCurrNamespace) ++ id.getId
327
+ if vis?.any (Β·.raw.isOfKind ``Parser.Command.private) then
328
+ fullId := mkPrivateName (← getEnv) fullId
329
+ -- We need to add `id`'s ranges *before* elaborating `initFn` (and then `id` itself) as
330
+ -- otherwise the info context created by `with_decl_name` will be incomplete and break the
331
+ -- call hierarchy
332
+ addDeclarationRangesForBuiltin fullId ⟨defStx.raw[0]⟩ defStx.raw[1]
333
+ elabCommand (← `(
334
+ $[unsafe%$unsafe?]? def initFn : IO $type := with_decl_name% $(mkIdent fullId) do $doSeq
335
+ $defStx:command))
336
+ else
337
+ let `(Parser.Command.declModifiersT| $[$doc?:docComment]? $[@[$attrs?,*]]? $(_)? $[unsafe%$unsafe?]?) := declModifiers
338
+ | throwErrorAt declModifiers "invalid initialization command, unexpected modifiers"
339
+ let attrs := (attrs?.map (Β·.getElems)).getD #[]
340
+ let attrs := attrs.push (← `(Lean.Parser.Term.attrInstance| $attrId:ident))
341
+ elabCommand (← `($[$doc?:docComment]? @[$[$attrs],*] $[unsafe%$unsafe?]? def initFn : IO Unit := do $doSeq))
342
+ | _ => throwUnsupportedSyntax
343
+
344
+ builtin_initialize
345
+ registerTraceClass `Elab.axiom
346
+
347
+ end Lean.Elab.Command
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/DeclarationRange.lean ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Log
8
+ import Lean.Parser.Command
9
+ import Lean.DeclarationRange
10
+ import Lean.Data.Lsp.Utf16
11
+
12
+ namespace Lean.Elab
13
+
14
+ def getDeclarationRange? [Monad m] [MonadFileMap m] (stx : Syntax) : m (Option DeclarationRange) := do
15
+ let some range := stx.getRange?
16
+ | return none
17
+ let fileMap ← getFileMap
18
+ return some <| .ofStringPositions fileMap range.start range.stop
19
+
20
+ /--
21
+ For most builtin declarations, the selection range is just its name, which is stored in the second position.
22
+ Example:
23
+ ```
24
+ "def " >> declId >> optDeclSig >> declVal
25
+ ```
26
+ If the declaration name is absent, we use the keyword instead.
27
+ This function converts the given `Syntax` into one that represents its "selection range".
28
+ -/
29
+ def getDeclarationSelectionRef (stx : Syntax) : Syntax :=
30
+ if stx.isOfKind ``Lean.Parser.Command.instance then
31
+ -- must skip `attrKind` and `optPrio` for `instance`
32
+ if !stx[3].isNone then
33
+ stx[3][0]
34
+ else
35
+ stx[1]
36
+ else
37
+ if stx[1][0].isIdent then
38
+ stx[1][0] -- `declId`
39
+ else if stx[1].isIdent then
40
+ stx[1] -- raw `ident`
41
+ else
42
+ stx[0]
43
+
44
+ /--
45
+ Derives and adds declaration ranges from given syntax trees. If `rangeStx` does not have a range,
46
+ nothing is added. If `selectionRangeStx` does not have a range, it is defaulted to that of
47
+ `rangeStx`.
48
+ -/
49
+ def addDeclarationRangesFromSyntax [Monad m] [MonadEnv m] [MonadFileMap m] (declName : Name)
50
+ (rangeStx : Syntax) (selectionRangeStx : Syntax := .missing) : m Unit := do
51
+ -- may fail on partial syntax, ignore in that case
52
+ let some range ← getDeclarationRange? rangeStx | return
53
+ let selectionRange ← (Β·.getD range) <$> getDeclarationRange? selectionRangeStx
54
+ Lean.addDeclarationRanges declName { range, selectionRange }
55
+
56
+ /--
57
+ Stores the `range` and `selectionRange` for `declName` where `modsStx` is the modifier part and
58
+ `cmdStx` the remaining part of the syntax tree for `declName`.
59
+
60
+ This method is for the builtin declarations only. User-defined commands should use
61
+ `Lean.Elab.addDeclarationRangesFromSyntax` or `Lean.addDeclarationRanges` to store this information
62
+ for their commands.
63
+ -/
64
+ def addDeclarationRangesForBuiltin [Monad m] [MonadEnv m] [MonadFileMap m] (declName : Name)
65
+ (modsStx : TSyntax ``Parser.Command.declModifiers) (declStx : Syntax) : m Unit := do
66
+ if declStx.getKind == ``Parser.Command.Β«exampleΒ» then
67
+ return ()
68
+ let stx := mkNullNode #[modsStx, declStx]
69
+ addDeclarationRangesFromSyntax declName stx (getDeclarationSelectionRef declStx)
70
+
71
+ end Lean.Elab
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/DefView.lean ADDED
@@ -0,0 +1,232 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2020 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Sebastian Ullrich
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Command
8
+ import Lean.Elab.DeclNameGen
9
+ import Lean.Elab.DeclUtil
10
+
11
+ namespace Lean.Elab
12
+
13
+ inductive DefKind where
14
+ | def | instance | theorem | example | opaque | abbrev
15
+ deriving Inhabited, BEq
16
+
17
+ def DefKind.isTheorem : DefKind β†’ Bool
18
+ | .theorem => true
19
+ | _ => false
20
+
21
+ def DefKind.isExample : DefKind β†’ Bool
22
+ | .example => true
23
+ | _ => false
24
+
25
+ /-- Header elaboration data of a `DefView`. -/
26
+ structure DefViewElabHeaderData where
27
+ /--
28
+ Short name. Recall that all declarations in Lean 4 are potentially recursive. We use `shortDeclName` to refer
29
+ to them at `valueStx`, and other declarations in the same mutual block. -/
30
+ shortDeclName : Name
31
+ /-- Full name for this declaration. This is the name that will be added to the `Environment`. -/
32
+ declName : Name
33
+ /-- Universe level parameter names explicitly provided by the user. -/
34
+ levelNames : List Name
35
+ /-- Syntax objects for the binders occurring before `:`, we use them to populate the `InfoTree` when elaborating `valueStx`. -/
36
+ binderIds : Array Syntax
37
+ /-- Number of parameters before `:`, it also includes auto-implicit parameters automatically added by Lean. -/
38
+ numParams : Nat
39
+ /-- Type including parameters. -/
40
+ type : Expr
41
+ deriving Inhabited
42
+
43
+ section Snapshots
44
+ open Language
45
+
46
+ /-- Snapshot after processing of a definition body. -/
47
+ structure BodyProcessedSnapshot extends Language.Snapshot where
48
+ /-- State after elaboration. -/
49
+ state : Term.SavedState
50
+ /-- Elaboration result. -/
51
+ value : Expr
52
+ /-- Untyped snapshots from `logSnapshotTask`, saved at this level for cancellation. -/
53
+ moreSnaps : Array (SnapshotTask SnapshotTree)
54
+ deriving Nonempty
55
+ instance : Language.ToSnapshotTree BodyProcessedSnapshot where
56
+ toSnapshotTree s := ⟨s.toSnapshot, s.moreSnaps⟩
57
+
58
+ /-- Snapshot after elaboration of a definition header. -/
59
+ structure HeaderProcessedSnapshot extends Language.Snapshot where
60
+ /-- Elaboration results. -/
61
+ view : DefViewElabHeaderData
62
+ /-- Resulting elaboration state, including any environment additions. -/
63
+ state : Term.SavedState
64
+ /-- Syntax of top-level tactic block if any, for checking reuse of `tacSnap?`. -/
65
+ tacStx? : Option Syntax
66
+ /-- Incremental execution of main tactic block, if any. -/
67
+ tacSnap? : Option (SnapshotTask Tactic.TacticParsedSnapshot)
68
+ /-- Syntax of definition body, for checking reuse of `bodySnap`. -/
69
+ bodyStx : Syntax
70
+ /-- Result of body elaboration. -/
71
+ bodySnap : SnapshotTask (Option BodyProcessedSnapshot)
72
+ /-- Untyped snapshots from `logSnapshotTask`, saved at this level for cancellation. -/
73
+ moreSnaps : Array (SnapshotTask SnapshotTree)
74
+ deriving Nonempty
75
+ instance : Language.ToSnapshotTree HeaderProcessedSnapshot where
76
+ toSnapshotTree s := ⟨s.toSnapshot,
77
+ (match s.tacSnap? with
78
+ | some tac => #[tac.map (sync := true) toSnapshotTree]
79
+ | none => #[]) ++
80
+ #[s.bodySnap.map (sync := true) toSnapshotTree] ++ s.moreSnaps⟩
81
+
82
+ /-- State before elaboration of a mutual definition. -/
83
+ structure DefParsed where
84
+ /--
85
+ Unstructured syntax object comprising the full "header" of the definition from the modifiers
86
+ (incl. docstring) up to the value, used for determining header elaboration reuse.
87
+ -/
88
+ fullHeaderRef : Syntax
89
+ /-- Elaboration result, unless fatal exception occurred. -/
90
+ headerProcessedSnap : SnapshotTask (Option HeaderProcessedSnapshot)
91
+ deriving Nonempty
92
+
93
+ /-- Snapshot after syntax tree has been split into separate mutual def headers. -/
94
+ structure DefsParsedSnapshot extends Language.Snapshot where
95
+ /-- Definitions of this mutual block. -/
96
+ defs : Array DefParsed
97
+ deriving Nonempty, TypeName
98
+ instance : Language.ToSnapshotTree DefsParsedSnapshot where
99
+ toSnapshotTree s := ⟨s.toSnapshot,
100
+ s.defs.map (·.headerProcessedSnap.map (sync := true) toSnapshotTree)⟩
101
+
102
+ end Snapshots
103
+
104
+ structure DefView where
105
+ kind : DefKind
106
+ ref : Syntax
107
+ /--
108
+ An unstructured syntax object that comprises the "header" of the definition, i.e. everything up
109
+ to the value. Used as a more specific ref for header elaboration.
110
+ -/
111
+ headerRef : Syntax
112
+ modifiers : Modifiers
113
+ declId : Syntax
114
+ binders : Syntax
115
+ type? : Option Syntax
116
+ value : Syntax
117
+ /--
118
+ Snapshot for incremental processing of this definition.
119
+
120
+ Invariant: If the bundle's `old?` is set, then elaboration of the header is guaranteed to result
121
+ in the same elaboration result and state, i.e. reuse is possible.
122
+ -/
123
+ headerSnap? : Option (Language.SnapshotBundle (Option HeaderProcessedSnapshot)) := none
124
+ deriving? : Option (Array Syntax) := none
125
+ deriving Inhabited
126
+
127
+ def DefView.isInstance (view : DefView) : Bool :=
128
+ view.modifiers.attrs.any fun attr => attr.name == `instance
129
+
130
+ /-- Prepends the `defeq` attribute, removing existing ones if there are any -/
131
+ def DefView.markDefEq (view : DefView) : DefView :=
132
+ { view with modifiers :=
133
+ view.modifiers.filterAttrs (Β·.name != `defeq) |>.addFirstAttr { name := `defeq } }
134
+
135
+ namespace Command
136
+ open Meta
137
+
138
+ def mkDefViewOfAbbrev (modifiers : Modifiers) (stx : Syntax) : DefView :=
139
+ -- leading_parser "abbrev " >> declId >> optDeclSig >> declVal
140
+ let (binders, type) := expandOptDeclSig stx[2]
141
+ let modifiers := modifiers.addAttr { name := `inline }
142
+ let modifiers := modifiers.addAttr { name := `reducible }
143
+ { ref := stx, headerRef := mkNullNode stx.getArgs[*...3], kind := DefKind.abbrev, modifiers,
144
+ declId := stx[1], binders, type? := type, value := stx[3] }
145
+
146
+ def mkDefViewOfDef (modifiers : Modifiers) (stx : Syntax) : DefView :=
147
+ -- leading_parser "def " >> declId >> optDeclSig >> declVal >> optDefDeriving
148
+ let (binders, type) := expandOptDeclSig stx[2]
149
+ let deriving? := if stx[4].isNone then none else some stx[4][1].getSepArgs
150
+ { ref := stx, headerRef := mkNullNode stx.getArgs[*...3], kind := DefKind.def, modifiers,
151
+ declId := stx[1], binders, type? := type, value := stx[3], deriving? }
152
+
153
+ def mkDefViewOfTheorem (modifiers : Modifiers) (stx : Syntax) : DefView :=
154
+ -- leading_parser "theorem " >> declId >> declSig >> declVal
155
+ let (binders, type) := expandDeclSig stx[2]
156
+ { ref := stx, headerRef := mkNullNode stx.getArgs[*...3], kind := DefKind.theorem, modifiers,
157
+ declId := stx[1], binders, type? := some type, value := stx[3] }
158
+
159
+ def mkDefViewOfInstance (modifiers : Modifiers) (stx : Syntax) : CommandElabM DefView := do
160
+ -- leading_parser Term.attrKind >> "instance " >> optNamedPrio >> optional declId >> declSig >> declVal
161
+ let attrKind ← liftMacroM <| toAttributeKind stx[0]
162
+ let prio ← liftMacroM <| expandOptNamedPrio stx[2]
163
+ let attrStx ← `(attr| instance $(quote prio):num)
164
+ let (binders, type) := expandDeclSig stx[4]
165
+ let modifiers := modifiers.addAttr { kind := attrKind, name := `instance, stx := attrStx }
166
+ let declId ← match stx[3].getOptional? with
167
+ | some declId =>
168
+ if ← isTracingEnabledFor `Elab.instance.mkInstanceName then
169
+ let id ← mkInstanceName binders.getArgs type
170
+ trace[Elab.instance.mkInstanceName] "generated {(← getCurrNamespace) ++ id} for {declId}"
171
+ pure declId
172
+ | none =>
173
+ let id ← mkInstanceName binders.getArgs type
174
+ trace[Elab.instance.mkInstanceName] "generated {(← getCurrNamespace) ++ id}"
175
+ pure <| mkNode ``Parser.Command.declId #[mkIdentFrom stx[1] id (canonical := true), mkNullNode]
176
+ return {
177
+ ref := stx, headerRef := mkNullNode stx.getArgs[*...5], kind := DefKind.instance, modifiers := modifiers,
178
+ declId := declId, binders := binders, type? := type, value := stx[5]
179
+ }
180
+
181
+ def mkDefViewOfOpaque (modifiers : Modifiers) (stx : Syntax) : CommandElabM DefView := do
182
+ -- leading_parser "opaque " >> declId >> declSig >> optional declValSimple
183
+ let (binders, type) := expandDeclSig stx[2]
184
+ let val ← match stx[3].getOptional? with
185
+ | some val => pure val
186
+ | none =>
187
+ let val ← if modifiers.isUnsafe then `(default_or_ofNonempty% unsafe) else `(default_or_ofNonempty%)
188
+ `(Parser.Command.declValSimple| := $val)
189
+ return {
190
+ ref := stx, headerRef := mkNullNode stx.getArgs[*...3], kind := DefKind.opaque, modifiers := modifiers,
191
+ declId := stx[1], binders := binders, type? := some type, value := val
192
+ }
193
+
194
+ def mkDefViewOfExample (modifiers : Modifiers) (stx : Syntax) : DefView :=
195
+ -- leading_parser "example " >> declSig >> declVal
196
+ let (binders, type) := expandOptDeclSig stx[1]
197
+ let id := mkIdentFrom stx[0] `_example (canonical := true)
198
+ let declId := mkNode ``Parser.Command.declId #[id, mkNullNode]
199
+ { ref := stx, headerRef := mkNullNode stx.getArgs[*...2], kind := DefKind.example, modifiers := modifiers,
200
+ declId := declId, binders := binders, type? := type, value := stx[2] }
201
+
202
+ def isDefLike (stx : Syntax) : Bool :=
203
+ let declKind := stx.getKind
204
+ declKind == ``Parser.Command.abbrev ||
205
+ declKind == ``Parser.Command.definition ||
206
+ declKind == ``Parser.Command.theorem ||
207
+ declKind == ``Parser.Command.opaque ||
208
+ declKind == ``Parser.Command.instance ||
209
+ declKind == ``Parser.Command.example
210
+
211
+ def mkDefView (modifiers : Modifiers) (stx : Syntax) : CommandElabM DefView :=
212
+ let declKind := stx.getKind
213
+ if declKind == ``Parser.Command.Β«abbrevΒ» then
214
+ return mkDefViewOfAbbrev modifiers stx
215
+ else if declKind == ``Parser.Command.definition then
216
+ return mkDefViewOfDef modifiers stx
217
+ else if declKind == ``Parser.Command.theorem then
218
+ return mkDefViewOfTheorem modifiers stx
219
+ else if declKind == ``Parser.Command.opaque then
220
+ mkDefViewOfOpaque modifiers stx
221
+ else if declKind == ``Parser.Command.instance then
222
+ mkDefViewOfInstance modifiers stx
223
+ else if declKind == ``Parser.Command.example then
224
+ return mkDefViewOfExample modifiers stx
225
+ else
226
+ throwError "unexpected kind of definition"
227
+
228
+ builtin_initialize registerTraceClass `Elab.definition
229
+ builtin_initialize registerTraceClass `Elab.instance.mkInstanceName
230
+
231
+ end Command
232
+ end Lean.Elab
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Deriving.lean ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2020 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Deriving.Basic
8
+ import Lean.Elab.Deriving.Util
9
+ import Lean.Elab.Deriving.Inhabited
10
+ import Lean.Elab.Deriving.Nonempty
11
+ import Lean.Elab.Deriving.TypeName
12
+ import Lean.Elab.Deriving.BEq
13
+ import Lean.Elab.Deriving.DecEq
14
+ import Lean.Elab.Deriving.Repr
15
+ import Lean.Elab.Deriving.FromToJson
16
+ import Lean.Elab.Deriving.SizeOf
17
+ import Lean.Elab.Deriving.Hashable
18
+ import Lean.Elab.Deriving.Ord
19
+ import Lean.Elab.Deriving.ToExpr
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Do.lean ADDED
@@ -0,0 +1,1827 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2020 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Term
8
+ import Lean.Elab.BindersUtil
9
+ import Lean.Elab.PatternVar
10
+ import Lean.Elab.Quotation.Util
11
+ import Lean.Parser.Do
12
+
13
+ -- HACK: avoid code explosion until heuristics are improved
14
+ set_option compiler.reuse false
15
+
16
+ namespace Lean.Elab.Term
17
+ open Lean.Parser.Term
18
+ open Meta
19
+ open TSyntax.Compat
20
+
21
+ private def getDoSeqElems (doSeq : Syntax) : List Syntax :=
22
+ if doSeq.getKind == ``Parser.Term.doSeqBracketed then
23
+ doSeq[1].getArgs.toList.map fun arg => arg[0]
24
+ else if doSeq.getKind == ``Parser.Term.doSeqIndent then
25
+ doSeq[0].getArgs.toList.map fun arg => arg[0]
26
+ else
27
+ []
28
+
29
+ private def getDoSeq (doStx : Syntax) : Syntax :=
30
+ doStx[1]
31
+
32
+ @[builtin_term_elab liftMethod] def elabLiftMethod : TermElab := fun stx _ =>
33
+ throwErrorAt stx "invalid use of `(<- ...)`, must be nested inside a 'do' expression"
34
+
35
+ /-- Return true if we should not lift `(<- ...)` actions nested in the syntax nodes with the given kind. -/
36
+ private def liftMethodDelimiter (k : SyntaxNodeKind) : Bool :=
37
+ k == ``Parser.Term.do ||
38
+ k == ``Parser.Term.doSeqIndent ||
39
+ k == ``Parser.Term.doSeqBracketed ||
40
+ k == ``Parser.Term.termReturn ||
41
+ k == ``Parser.Term.termUnless ||
42
+ k == ``Parser.Term.termTry ||
43
+ k == ``Parser.Term.termFor
44
+
45
+ /-- Given `stx` which is a `letPatDecl`, `letEqnsDecl`, or `letIdDecl`, return true if it has binders. -/
46
+ private def letDeclArgHasBinders (letDeclArg : Syntax) : Bool :=
47
+ let k := letDeclArg.getKind
48
+ if k == ``Parser.Term.letPatDecl then
49
+ false
50
+ else if k == ``Parser.Term.letEqnsDecl then
51
+ true
52
+ else if k == ``Parser.Term.letIdDecl then
53
+ -- letIdLhs := binderIdent >> checkWsBefore "expected space before binders" >> many (ppSpace >> letIdBinder)) >> optType
54
+ let binders := letDeclArg[1]
55
+ binders.getNumArgs > 0
56
+ else
57
+ false
58
+
59
+ /-- Return `true` if the given `letDecl` contains binders. -/
60
+ private def letDeclHasBinders (letDecl : Syntax) : Bool :=
61
+ letDeclArgHasBinders letDecl[0]
62
+
63
+ /-- Return true if we should generate an error message when lifting a method over this kind of syntax. -/
64
+ private def liftMethodForbiddenBinder (stx : Syntax) : Bool :=
65
+ let k := stx.getKind
66
+ -- TODO: make this extensible in the future.
67
+ if k == ``Parser.Term.fun || k == ``Parser.Term.matchAlts ||
68
+ k == ``Parser.Term.doLetRec || k == ``Parser.Term.letrec then
69
+ -- It is never ok to lift over this kind of binder
70
+ true
71
+ -- The following kinds of `let`-expressions require extra checks to decide whether they contain binders or not
72
+ else if k == ``Parser.Term.let then
73
+ letDeclHasBinders stx[1]
74
+ else if k == ``Parser.Term.doLet then
75
+ letDeclHasBinders stx[2]
76
+ else if k == ``Parser.Term.doLetArrow then
77
+ letDeclArgHasBinders stx[2]
78
+ else
79
+ false
80
+
81
+ -- TODO: we must track whether we are inside a quotation or not.
82
+ private partial def hasLiftMethod : Syntax β†’ Bool
83
+ | Syntax.node _ k args =>
84
+ if liftMethodDelimiter k then false
85
+ -- NOTE: We don't check for lifts in quotations here, which doesn't break anything but merely makes this rare case a
86
+ -- bit slower
87
+ else if k == ``Parser.Term.liftMethod then true
88
+ -- For `pure` if-then-else, we only lift `(<- ...)` occurring in the condition.
89
+ else if k == ``termDepIfThenElse || k == ``termIfThenElse then args.size >= 2 && hasLiftMethod args[1]!
90
+ else args.any hasLiftMethod
91
+ | _ => false
92
+
93
+ structure ExtractMonadResult where
94
+ m : Expr
95
+ returnType : Expr
96
+ expectedType : Expr
97
+
98
+ private def mkUnknownMonadResult : MetaM ExtractMonadResult := do
99
+ let u ← mkFreshLevelMVar
100
+ let v ← mkFreshLevelMVar
101
+ let m ← mkFreshExprMVar (← mkArrow (mkSort (mkLevelSucc u)) (mkSort (mkLevelSucc v)))
102
+ let returnType ← mkFreshExprMVar (mkSort (mkLevelSucc u))
103
+ return { m, returnType, expectedType := mkApp m returnType }
104
+
105
+ private partial def extractBind (expectedType? : Option Expr) : TermElabM ExtractMonadResult := do
106
+ let some expectedType := expectedType? | mkUnknownMonadResult
107
+ let extractStep? (type : Expr) : MetaM (Option ExtractMonadResult) := do
108
+ let .app m returnType := type | return none
109
+ try
110
+ let bindInstType ← mkAppM ``Bind #[m]
111
+ discard <| Meta.synthInstance bindInstType
112
+ return some { m, returnType, expectedType }
113
+ catch _ =>
114
+ return none
115
+ let rec extract? (type : Expr) : MetaM (Option ExtractMonadResult) := do
116
+ match (← extractStep? type) with
117
+ | some r => return r
118
+ | none =>
119
+ let typeNew ← whnfCore type
120
+ if typeNew != type then
121
+ extract? typeNew
122
+ else
123
+ if typeNew.getAppFn.isMVar then
124
+ mkUnknownMonadResult
125
+ else match (← unfoldDefinition? typeNew) with
126
+ | some typeNew => extract? typeNew
127
+ | none => return none
128
+ match (← extract? expectedType) with
129
+ | some r => return r
130
+ | none => throwError "invalid `do` notation, expected type is not a monad application{indentExpr expectedType}\nYou can use the `do` notation in pure code by writing `Id.run do` instead of `do`, where `Id` is the identity monad."
131
+
132
+ namespace Do
133
+
134
+ abbrev Var := Syntax -- TODO: should be `Ident`
135
+
136
+ /-- A `doMatch` alternative. `vars` is the array of variables declared by `patterns`. -/
137
+ structure Alt (Οƒ : Type) where
138
+ ref : Syntax
139
+ vars : Array Var
140
+ patterns : Syntax
141
+ rhs : Οƒ
142
+ deriving Inhabited
143
+
144
+ /-- A `doMatchExpr` alternative. -/
145
+ structure AltExpr (Οƒ : Type) where
146
+ ref : Syntax
147
+ var? : Option Var
148
+ funName : Syntax
149
+ pvars : Array Syntax
150
+ rhs : Οƒ
151
+ deriving Inhabited
152
+
153
+ def AltExpr.vars (alt : AltExpr Οƒ) : Array Var := Id.run do
154
+ let mut vars := #[]
155
+ if let some var := alt.var? then
156
+ vars := vars.push var
157
+ for pvar in alt.pvars do
158
+ match pvar with
159
+ | `(_) => pure ()
160
+ | _ => vars := vars.push pvar
161
+ return vars
162
+
163
+ /--
164
+ Auxiliary datastructure for representing a `do` code block, and compiling "reassignments" (e.g., `x := x + 1`).
165
+ We convert `Code` into a `Syntax` term representing the:
166
+ - `do`-block, or
167
+ - the visitor argument for the `forIn` combinator.
168
+
169
+ We say the following constructors are terminals:
170
+ - `break`: for interrupting a `for x in s`
171
+ - `continue`: for interrupting the current iteration of a `for x in s`
172
+ - `return e`: for returning `e` as the result for the whole `do` computation block
173
+ - `action a`: for executing action `a` as a terminal
174
+ - `ite`: if-then-else
175
+ - `match`: pattern matching
176
+ - `jmp` a goto to a join-point
177
+
178
+ We say the terminals `break`, `continue`, `action`, and `return` are "exit points"
179
+
180
+ Note that, `return e` is not equivalent to `action (pure e)`. Here is an example:
181
+ ```
182
+ def f (x : Nat) : IO Unit := do
183
+ if x == 0 then
184
+ return ()
185
+ IO.println "hello"
186
+ ```
187
+ Executing `#eval f 0` will not print "hello". Now, consider
188
+ ```
189
+ def g (x : Nat) : IO Unit := do
190
+ if x == 0 then
191
+ pure ()
192
+ IO.println "hello"
193
+ ```
194
+ The `if` statement is essentially a noop, and "hello" is printed when we execute `g 0`.
195
+
196
+ - `decl` represents all declaration-like `doElem`s (e.g., `let`, `have`, `let rec`).
197
+ The field `stx` is the actual `doElem`,
198
+ `vars` is the array of variables declared by it, and `cont` is the next instruction in the `do` code block.
199
+ `vars` is an array since we have declarations such as `let (a, b) := s`.
200
+
201
+ - `reassign` is an reassignment-like `doElem` (e.g., `x := x + 1`).
202
+
203
+ - `joinpoint` is a join point declaration: an auxiliary `let`-declaration used to represent the control-flow.
204
+
205
+ - `seq a k` executes action `a`, ignores its result, and then executes `k`.
206
+ We also store the do-elements `dbg_trace` and `assert!` as actions in a `seq`.
207
+
208
+ A code block `C` is well-formed if
209
+ - For every `jmp ref j as` in `C`, there is a `joinpoint j ps b k` and `jmp ref j as` is in `k`, and
210
+ `ps.size == as.size` -/
211
+ inductive Code where
212
+ | decl (xs : Array Var) (doElem : Syntax) (k : Code)
213
+ | reassign (xs : Array Var) (doElem : Syntax) (k : Code)
214
+ /-- The Boolean value in `params` indicates whether we should use `(x : typeof! x)` when generating term Syntax or not -/
215
+ | joinpoint (name : Name) (params : Array (Var Γ— Bool)) (body : Code) (k : Code)
216
+ | seq (action : Syntax) (k : Code)
217
+ | action (action : Syntax)
218
+ | break (ref : Syntax)
219
+ | continue (ref : Syntax)
220
+ | return (ref : Syntax) (val : Syntax)
221
+ /-- Recall that an if-then-else may declare a variable using `optIdent` for the branches `thenBranch` and `elseBranch`. We store the variable name at `var?`. -/
222
+ | ite (ref : Syntax) (h? : Option Var) (optIdent : Syntax) (cond : Syntax) (thenBranch : Code) (elseBranch : Code)
223
+ | match (ref : Syntax) (gen : Syntax) (discrs : Syntax) (optMotive : Syntax) (alts : Array (Alt Code))
224
+ | matchExpr (ref : Syntax) (Β«metaΒ» : Bool) (discr : Syntax) (alts : Array (AltExpr Code)) (elseBranch : Code)
225
+ | jmp (ref : Syntax) (jpName : Name) (args : Array Syntax)
226
+ deriving Inhabited
227
+
228
+ def Code.getRef? : Code β†’ Option Syntax
229
+ | .decl _ doElem _ => doElem
230
+ | .reassign _ doElem _ => doElem
231
+ | .joinpoint .. => none
232
+ | .seq a _ => a
233
+ | .action a => a
234
+ | .break ref => ref
235
+ | .continue ref => ref
236
+ | .return ref _ => ref
237
+ | .ite ref .. => ref
238
+ | .match ref .. => ref
239
+ | .matchExpr ref .. => ref
240
+ | .jmp ref .. => ref
241
+
242
+ abbrev VarSet := RBMap Name Syntax Name.cmp
243
+
244
+ /-- A code block, and the collection of variables updated by it. -/
245
+ structure CodeBlock where
246
+ code : Code
247
+ uvars : VarSet := {} -- set of variables updated by `code`
248
+
249
+ private def varSetToArray (s : VarSet) : Array Var :=
250
+ s.fold (fun xs _ x => xs.push x) #[]
251
+
252
+ private def varsToMessageData (vars : Array Var) : MessageData :=
253
+ MessageData.joinSep (vars.toList.map fun n => MessageData.ofName (n.getId.simpMacroScopes)) " "
254
+
255
+ partial def CodeBlocl.toMessageData (codeBlock : CodeBlock) : MessageData :=
256
+ let us := MessageData.ofList <| (varSetToArray codeBlock.uvars).toList.map MessageData.ofSyntax
257
+ let rec loop : Code β†’ MessageData
258
+ | .decl xs _ k => m!"let {varsToMessageData xs} := ...\n{loop k}"
259
+ | .reassign xs _ k => m!"{varsToMessageData xs} := ...\n{loop k}"
260
+ | .joinpoint n ps body k => m!"let {n.simpMacroScopes} {varsToMessageData (ps.map Prod.fst)} := {indentD (loop body)}\n{loop k}"
261
+ | .seq e k => m!"{e}\n{loop k}"
262
+ | .action e => e
263
+ | .ite _ _ _ c t e => m!"if {c} then {indentD (loop t)}\nelse{loop e}"
264
+ | .jmp _ j xs => m!"jmp {j.simpMacroScopes} {xs.toList}"
265
+ | .break _ => m!"break {us}"
266
+ | .continue _ => m!"continue {us}"
267
+ | .return _ v => m!"return {v} {us}"
268
+ | .match _ _ ds _ alts =>
269
+ m!"match {ds} with"
270
+ ++ alts.foldl (init := m!"") fun acc alt => acc ++ m!"\n| {alt.patterns} => {loop alt.rhs}"
271
+ | .matchExpr _ Β«metaΒ» d alts elseCode =>
272
+ let r := m!"match_expr {if Β«metaΒ» then "" else "(meta := false)"} {d} with"
273
+ let r := r ++ alts.foldl (init := m!"") fun acc alt =>
274
+ let acc := acc ++ m!"\n| {if let some var := alt.var? then m!"{var}@" else ""}"
275
+ let acc := acc ++ m!"{alt.funName}"
276
+ let acc := acc ++ alt.pvars.foldl (init := m!"") fun acc pvar => acc ++ m!" {pvar}"
277
+ acc ++ m!" => {loop alt.rhs}"
278
+ r ++ m!"| _ => {loop elseCode}"
279
+ loop codeBlock.code
280
+
281
+ /-- Return true if the give code contains an exit point that satisfies `p` -/
282
+ partial def hasExitPointPred (c : Code) (p : Code β†’ Bool) : Bool :=
283
+ let rec loop : Code β†’ Bool
284
+ | .decl _ _ k => loop k
285
+ | .reassign _ _ k => loop k
286
+ | .joinpoint _ _ b k => loop b || loop k
287
+ | .seq _ k => loop k
288
+ | .ite _ _ _ _ t e => loop t || loop e
289
+ | .match _ _ _ _ alts => alts.any (loop Β·.rhs)
290
+ | .matchExpr _ _ _ alts e => alts.any (loop Β·.rhs) || loop e
291
+ | .jmp .. => false
292
+ | c => p c
293
+ loop c
294
+
295
+ def hasExitPoint (c : Code) : Bool :=
296
+ hasExitPointPred c fun _ => true
297
+
298
+ def hasReturn (c : Code) : Bool :=
299
+ hasExitPointPred c fun
300
+ | .return .. => true
301
+ | _ => false
302
+
303
+ def hasTerminalAction (c : Code) : Bool :=
304
+ hasExitPointPred c fun
305
+ | .action _ => true
306
+ | _ => false
307
+
308
+ def hasBreakContinue (c : Code) : Bool :=
309
+ hasExitPointPred c fun
310
+ | .break _ => true
311
+ | .continue _ => true
312
+ | _ => false
313
+
314
+ def hasBreakContinueReturn (c : Code) : Bool :=
315
+ hasExitPointPred c fun
316
+ | .break _ => true
317
+ | .continue _ => true
318
+ | .return _ _ => true
319
+ | _ => false
320
+
321
+ def mkAuxDeclFor {m} [Monad m] [MonadQuotation m] (e : Syntax) (mkCont : Syntax β†’ m Code) : m Code := withRef e <| withFreshMacroScope do
322
+ let y ← `(y)
323
+ let doElem ← `(doElem| let y ← $e:term)
324
+ -- Add elaboration hint for producing sane error message
325
+ let y ← `(ensure_expected_type% "type mismatch, result value" $y)
326
+ let k ← mkCont y
327
+ return .decl #[y] doElem k
328
+
329
+ /-- Convert `action _ e` instructions in `c` into `let y ← e; jmp _ jp (xs y)`. -/
330
+ partial def convertTerminalActionIntoJmp (code : Code) (jp : Name) (xs : Array Var) : MacroM Code :=
331
+ let rec loop : Code β†’ MacroM Code
332
+ | .decl xs stx k => return .decl xs stx (← loop k)
333
+ | .reassign xs stx k => return .reassign xs stx (← loop k)
334
+ | .joinpoint n ps b k => return .joinpoint n ps (← loop b) (← loop k)
335
+ | .seq e k => return .seq e (← loop k)
336
+ | .ite ref x? h c t e => return .ite ref x? h c (← loop t) (← loop e)
337
+ | .action e => mkAuxDeclFor e fun y =>
338
+ let ref := e
339
+ -- We jump to `jp` with xs **and** y
340
+ let jmpArgs := xs.push y
341
+ return Code.jmp ref jp jmpArgs
342
+ | .match ref g ds t alts =>
343
+ return .match ref g ds t (← alts.mapM fun alt => do pure { alt with rhs := (← loop alt.rhs) })
344
+ | .matchExpr ref Β«metaΒ» d alts e => do
345
+ let alts ← alts.mapM fun alt => do pure { alt with rhs := (← loop alt.rhs) }
346
+ let e ← loop e
347
+ return .matchExpr ref Β«metaΒ» d alts e
348
+ | c => return c
349
+ loop code
350
+
351
+ structure JPDecl where
352
+ name : Name
353
+ params : Array (Var Γ— Bool)
354
+ body : Code
355
+
356
+ def attachJP (jpDecl : JPDecl) (k : Code) : Code :=
357
+ Code.joinpoint jpDecl.name jpDecl.params jpDecl.body k
358
+
359
+ def attachJPs (jpDecls : Array JPDecl) (k : Code) : Code :=
360
+ jpDecls.foldr attachJP k
361
+
362
+ def mkFreshJP (ps : Array (Var Γ— Bool)) (body : Code) : TermElabM JPDecl := do
363
+ let ps ← if ps.isEmpty then
364
+ let y ← `(y)
365
+ pure #[(y.raw, false)]
366
+ else
367
+ pure ps
368
+ -- Remark: the compiler frontend implemented in C++ currently detects jointpoints created by
369
+ -- the "do" notation by testing the name. See hack at method `visit_let` at `lcnf.cpp`
370
+ -- We will remove this hack when we re-implement the compiler frontend in Lean.
371
+ let name ← mkFreshUserName `__do_jp
372
+ pure { name := name, params := ps, body := body }
373
+
374
+ def addFreshJP (ps : Array (Var Γ— Bool)) (body : Code) : StateRefT (Array JPDecl) TermElabM Name := do
375
+ let jp ← mkFreshJP ps body
376
+ modify fun (jps : Array JPDecl) => jps.push jp
377
+ pure jp.name
378
+
379
+ def insertVars (rs : VarSet) (xs : Array Var) : VarSet :=
380
+ xs.foldl (fun rs x => rs.insert x.getId x) rs
381
+
382
+ def eraseVars (rs : VarSet) (xs : Array Var) : VarSet :=
383
+ xs.foldl (Β·.erase Β·.getId) rs
384
+
385
+ def eraseOptVar (rs : VarSet) (x? : Option Var) : VarSet :=
386
+ match x? with
387
+ | none => rs
388
+ | some x => rs.insert x.getId x
389
+
390
+ /-- Create a new jointpoint for `c`, and jump to it with the variables `rs` -/
391
+ def mkSimpleJmp (ref : Syntax) (rs : VarSet) (c : Code) : StateRefT (Array JPDecl) TermElabM Code := do
392
+ let xs := varSetToArray rs
393
+ let jp ← addFreshJP (xs.map fun x => (x, true)) c
394
+ if xs.isEmpty then
395
+ let unit ← ``(Unit.unit)
396
+ return Code.jmp ref jp #[unit]
397
+ else
398
+ return Code.jmp ref jp xs
399
+
400
+ /-- Create a new joinpoint that takes `rs` and `val` as arguments. `val` must be syntax representing a pure value.
401
+ The body of the joinpoint is created using `mkJPBody yFresh`, where `yFresh`
402
+ is a fresh variable created by this method. -/
403
+ def mkJmp (ref : Syntax) (rs : VarSet) (val : Syntax) (mkJPBody : Syntax β†’ MacroM Code) : StateRefT (Array JPDecl) TermElabM Code := do
404
+ let xs := varSetToArray rs
405
+ let args := xs.push val
406
+ let yFresh ← withRef ref `(y)
407
+ let ps := xs.map fun x => (x, true)
408
+ let ps := ps.push (yFresh, false)
409
+ let jpBody ← liftMacroM <| mkJPBody yFresh
410
+ let jp ← addFreshJP ps jpBody
411
+ return Code.jmp ref jp args
412
+
413
+ /-- `pullExitPointsAux rs c` auxiliary method for `pullExitPoints`, `rs` is the set of update variable in the current path. -/
414
+ partial def pullExitPointsAux (rs : VarSet) (c : Code) : StateRefT (Array JPDecl) TermElabM Code := do
415
+ match c with
416
+ | .decl xs stx k => return .decl xs stx (← pullExitPointsAux (eraseVars rs xs) k)
417
+ | .reassign xs stx k => return .reassign xs stx (← pullExitPointsAux (insertVars rs xs) k)
418
+ | .joinpoint j ps b k => return .joinpoint j ps (← pullExitPointsAux rs b) (← pullExitPointsAux rs k)
419
+ | .seq e k => return .seq e (← pullExitPointsAux rs k)
420
+ | .ite ref x? o c t e => return .ite ref x? o c (← pullExitPointsAux (eraseOptVar rs x?) t) (← pullExitPointsAux (eraseOptVar rs x?) e)
421
+ | .jmp .. => return c
422
+ | .break ref => mkSimpleJmp ref rs (.break ref)
423
+ | .continue ref => mkSimpleJmp ref rs (.continue ref)
424
+ | .return ref val => mkJmp ref rs val (fun y => return .return ref y)
425
+ | .action e =>
426
+ -- We use `mkAuxDeclFor` because `e` is not pure.
427
+ mkAuxDeclFor e fun y =>
428
+ let ref := e
429
+ mkJmp ref rs y (fun yFresh => return .action (← ``(Pure.pure $yFresh)))
430
+ | .match ref g ds t alts =>
431
+ let alts ← alts.mapM fun alt => do pure { alt with rhs := (← pullExitPointsAux (eraseVars rs alt.vars) alt.rhs) }
432
+ return .match ref g ds t alts
433
+ | .matchExpr ref Β«metaΒ» d alts e =>
434
+ let alts ← alts.mapM fun alt => do pure { alt with rhs := (← pullExitPointsAux (eraseVars rs alt.vars) alt.rhs) }
435
+ let e ← pullExitPointsAux rs e
436
+ return .matchExpr ref Β«metaΒ» d alts e
437
+
438
+ /--
439
+ Auxiliary operation for adding new variables to the collection of updated variables in a CodeBlock.
440
+ When a new variable is not already in the collection, but is shadowed by some declaration in `c`,
441
+ we create auxiliary join points to make sure we preserve the semantics of the code block.
442
+ Example: suppose we have the code block `print x; let x := 10; return x`. And we want to extend it
443
+ with the reassignment `x := x + 1`. We first use `pullExitPoints` to create
444
+ ```
445
+ let jp (x!1) := return x!1;
446
+ print x;
447
+ let x := 10;
448
+ jmp jp x
449
+ ```
450
+ and then we add the reassignment
451
+ ```
452
+ x := x + 1
453
+ let jp (x!1) := return x!1;
454
+ print x;
455
+ let x := 10;
456
+ jmp jp x
457
+ ```
458
+ Note that we created a fresh variable `x!1` to avoid accidental name capture.
459
+ As another example, consider
460
+ ```
461
+ print x;
462
+ let x := 10
463
+ y := y + 1;
464
+ return x;
465
+ ```
466
+ We transform it into
467
+ ```
468
+ let jp (y x!1) := return x!1;
469
+ print x;
470
+ let x := 10
471
+ y := y + 1;
472
+ jmp jp y x
473
+ ```
474
+ and then we add the reassignment as in the previous example.
475
+ We need to include `y` in the jump, because each exit point is implicitly returning the set of
476
+ update variables.
477
+
478
+ We implement the method as follows. Let `us` be `c.uvars`, then
479
+ 1- for each `return _ y` in `c`, we create a join point
480
+ `let j (us y!1) := return y!1`
481
+ and replace the `return _ y` with `jmp us y`
482
+ 2- for each `break`, we create a join point
483
+ `let j (us) := break`
484
+ and replace the `break` with `jmp us`.
485
+ 3- Same as 2 for `continue`.
486
+ -/
487
+ def pullExitPoints (c : Code) : TermElabM Code := do
488
+ if hasExitPoint c then
489
+ let (c, jpDecls) ← (pullExitPointsAux {} c).run #[]
490
+ return attachJPs jpDecls c
491
+ else
492
+ return c
493
+
494
+ partial def extendUpdatedVarsAux (c : Code) (ws : VarSet) : TermElabM Code :=
495
+ let rec update (c : Code) : TermElabM Code := do
496
+ match c with
497
+ | .joinpoint j ps b k => return .joinpoint j ps (← update b) (← update k)
498
+ | .seq e k => return .seq e (← update k)
499
+ | .match ref g ds t alts =>
500
+ if alts.any fun alt => alt.vars.any fun x => ws.contains x.getId then
501
+ -- If a pattern variable is shadowing a variable in ws, we `pullExitPoints`
502
+ pullExitPoints c
503
+ else
504
+ return .match ref g ds t (← alts.mapM fun alt => do pure { alt with rhs := (← update alt.rhs) })
505
+ | .matchExpr ref Β«metaΒ» d alts e =>
506
+ if alts.any fun alt => alt.vars.any fun x => ws.contains x.getId then
507
+ -- If a pattern variable is shadowing a variable in ws, we `pullExitPoints`
508
+ pullExitPoints c
509
+ else
510
+ let alts ← alts.mapM fun alt => do pure { alt with rhs := (← update alt.rhs) }
511
+ let e ← update e
512
+ return .matchExpr ref Β«metaΒ» d alts e
513
+ | .ite ref none o c t e => return .ite ref none o c (← update t) (← update e)
514
+ | .ite ref (some h) o cond t e =>
515
+ if ws.contains h.getId then
516
+ -- if the `h` at `if h : c then t else e` shadows a variable in `ws`, we `pullExitPoints`
517
+ pullExitPoints c
518
+ else
519
+ return Code.ite ref (some h) o cond (← update t) (← update e)
520
+ | .reassign xs stx k => return .reassign xs stx (← update k)
521
+ | .decl xs stx k => do
522
+ if xs.any fun x => ws.contains x.getId then
523
+ -- One the declared variables is shadowing a variable in `ws`
524
+ pullExitPoints c
525
+ else
526
+ return .decl xs stx (← update k)
527
+ | c => return c
528
+ update c
529
+
530
+ /--
531
+ Extend the set of updated variables. It assumes `ws` is a super set of `c.uvars`.
532
+ We **cannot** simply update the field `c.uvars`, because `c` may have shadowed some variable in `ws`.
533
+ See discussion at `pullExitPoints`.
534
+ -/
535
+ partial def extendUpdatedVars (c : CodeBlock) (ws : VarSet) : TermElabM CodeBlock := do
536
+ if ws.any fun x _ => !c.uvars.contains x then
537
+ -- `ws` contains a variable that is not in `c.uvars`, but in `c.dvars` (i.e., it has been shadowed)
538
+ pure { code := (← extendUpdatedVarsAux c.code ws), uvars := ws }
539
+ else
540
+ pure { c with uvars := ws }
541
+
542
+ private def union (s₁ sβ‚‚ : VarSet) : VarSet :=
543
+ s₁.fold (Β·.insert Β·) sβ‚‚
544
+
545
+ /--
546
+ Given two code blocks `c₁` and `cβ‚‚`, make sure they have the same set of updated variables.
547
+ Let `ws` the union of the updated variables in `c₁‡ and ‡cβ‚‚`.
548
+ We use `extendUpdatedVars c₁ ws` and `extendUpdatedVars cβ‚‚ ws`
549
+ -/
550
+ def homogenize (c₁ cβ‚‚ : CodeBlock) : TermElabM (CodeBlock Γ— CodeBlock) := do
551
+ let ws := union c₁.uvars cβ‚‚.uvars
552
+ let c₁ ← extendUpdatedVars c₁ ws
553
+ let cβ‚‚ ← extendUpdatedVars cβ‚‚ ws
554
+ pure (c₁, cβ‚‚)
555
+
556
+ /--
557
+ Extending code blocks with variable declarations: `let x : t := v` and `let x : t ← v`.
558
+ We remove `x` from the collection of updated variables.
559
+ Remark: `stx` is the syntax for the declaration (e.g., `letDecl`), and `xs` are the variables
560
+ declared by it. It is an array because we have let-declarations that declare multiple variables.
561
+ Example: `let (x, y) := t`
562
+ -/
563
+ def mkVarDeclCore (xs : Array Var) (stx : Syntax) (c : CodeBlock) : CodeBlock := {
564
+ code := Code.decl xs stx c.code,
565
+ uvars := eraseVars c.uvars xs
566
+ }
567
+
568
+ /--
569
+ Extending code blocks with reassignments: `x : t := v` and `x : t ← v`.
570
+ Remark: `stx` is the syntax for the declaration (e.g., `letDecl`), and `xs` are the variables
571
+ declared by it. It is an array because we have let-declarations that declare multiple variables.
572
+ Example: `(x, y) ← t`
573
+ -/
574
+ def mkReassignCore (xs : Array Var) (stx : Syntax) (c : CodeBlock) : TermElabM CodeBlock := do
575
+ let us := c.uvars
576
+ let ws := insertVars us xs
577
+ -- If `xs` contains a new updated variable, then we must use `extendUpdatedVars`.
578
+ -- See discussion at `pullExitPoints`
579
+ let code ← if xs.any fun x => !us.contains x.getId then extendUpdatedVarsAux c.code ws else pure c.code
580
+ pure { code := .reassign xs stx code, uvars := ws }
581
+
582
+ def mkSeq (action : Syntax) (c : CodeBlock) : CodeBlock :=
583
+ { c with code := .seq action c.code }
584
+
585
+ def mkTerminalAction (action : Syntax) : CodeBlock :=
586
+ { code := .action action }
587
+
588
+ def mkReturn (ref : Syntax) (val : Syntax) : CodeBlock :=
589
+ { code := .return ref val }
590
+
591
+ def mkBreak (ref : Syntax) : CodeBlock :=
592
+ { code := .break ref }
593
+
594
+ def mkContinue (ref : Syntax) : CodeBlock :=
595
+ { code := .continue ref }
596
+
597
+ def mkIte (ref : Syntax) (optIdent : Syntax) (cond : Syntax) (thenBranch : CodeBlock) (elseBranch : CodeBlock) : TermElabM CodeBlock := do
598
+ let x? := optIdent.getOptional?
599
+ let (thenBranch, elseBranch) ← homogenize thenBranch elseBranch
600
+ return {
601
+ code := .ite ref x? optIdent cond thenBranch.code elseBranch.code,
602
+ uvars := thenBranch.uvars,
603
+ }
604
+
605
+ private def mkUnit : MacroM Syntax :=
606
+ ``((⟨⟩ : PUnit))
607
+
608
+ private def mkPureUnit : MacroM Syntax :=
609
+ ``(pure PUnit.unit)
610
+
611
+ def mkPureUnitAction : MacroM CodeBlock := do
612
+ return mkTerminalAction (← mkPureUnit)
613
+
614
+ def mkUnless (cond : Syntax) (c : CodeBlock) : MacroM CodeBlock := do
615
+ let thenBranch ← mkPureUnitAction
616
+ return { c with code := .ite (← getRef) none mkNullNode cond thenBranch.code c.code }
617
+
618
+ def mkMatch (ref : Syntax) (genParam : Syntax) (discrs : Syntax) (optMotive : Syntax) (alts : Array (Alt CodeBlock)) : TermElabM CodeBlock := do
619
+ -- nary version of homogenize
620
+ let ws := alts.foldl (union Β· Β·.rhs.uvars) {}
621
+ let alts ← alts.mapM fun alt => do
622
+ let rhs ← extendUpdatedVars alt.rhs ws
623
+ return { ref := alt.ref, vars := alt.vars, patterns := alt.patterns, rhs := rhs.code : Alt Code }
624
+ return { code := .match ref genParam discrs optMotive alts, uvars := ws }
625
+
626
+ def mkMatchExpr (ref : Syntax) (Β«metaΒ» : Bool) (discr : Syntax) (alts : Array (AltExpr CodeBlock)) (elseBranch : CodeBlock) : TermElabM CodeBlock := do
627
+ -- nary version of homogenize
628
+ let ws := alts.foldl (union Β· Β·.rhs.uvars) {}
629
+ let ws := union ws elseBranch.uvars
630
+ let alts ← alts.mapM fun alt => do
631
+ let rhs ← extendUpdatedVars alt.rhs ws
632
+ return { alt with rhs := rhs.code : AltExpr Code }
633
+ let elseBranch ← extendUpdatedVars elseBranch ws
634
+ return { code := .matchExpr ref Β«metaΒ» discr alts elseBranch.code, uvars := ws }
635
+
636
+ /-- Return a code block that executes `terminal` and then `k` with the value produced by `terminal`.
637
+ This method assumes `terminal` is a terminal -/
638
+ def concat (terminal : CodeBlock) (kRef : Syntax) (y? : Option Var) (k : CodeBlock) : TermElabM CodeBlock := do
639
+ unless hasTerminalAction terminal.code do
640
+ throwErrorAt kRef "`do` element is unreachable"
641
+ let (terminal, k) ← homogenize terminal k
642
+ let xs := varSetToArray k.uvars
643
+ let y ← match y? with | some y => pure y | none => `(y)
644
+ let ps := xs.map fun x => (x, true)
645
+ let ps := ps.push (y, false)
646
+ let jpDecl ← mkFreshJP ps k.code
647
+ let jp := jpDecl.name
648
+ let terminal ← liftMacroM <| convertTerminalActionIntoJmp terminal.code jp xs
649
+ return { code := attachJP jpDecl terminal, uvars := k.uvars }
650
+
651
+ def getLetIdVars (letId : Syntax) : Array Var :=
652
+ assert! letId.isOfKind ``Parser.Term.letId
653
+ -- def letId := leading_parser binderIdent <|> hygieneInfo
654
+ if letId[0].isIdent then
655
+ #[letId[0]]
656
+ else if letId[0].isOfKind hygieneInfoKind then
657
+ #[HygieneInfo.mkIdent letId[0] `this (canonical := true)]
658
+ else
659
+ #[]
660
+
661
+ def getLetIdDeclVars (letIdDecl : Syntax) : Array Var :=
662
+ assert! letIdDecl.isOfKind ``Parser.Term.letIdDecl
663
+ -- def letIdLhs : Parser := letId >> many (ppSpace >> letIdBinder) >> optType
664
+ -- def letIdDecl := leading_parser letIdLhs >> " := " >> termParser
665
+ getLetIdVars letIdDecl[0]
666
+
667
+ -- support both regular and syntax match
668
+ def getPatternVarsEx (pattern : Syntax) : TermElabM (Array Var) :=
669
+ getPatternVars pattern <|>
670
+ Quotation.getPatternVars pattern
671
+
672
+ def getPatternsVarsEx (patterns : Array Syntax) : TermElabM (Array Var) :=
673
+ getPatternsVars patterns <|>
674
+ Quotation.getPatternsVars patterns
675
+
676
+ def getLetPatDeclVars (letPatDecl : Syntax) : TermElabM (Array Var) := do
677
+ -- def letPatDecl := leading_parser termParser >> pushNone >> optType >> " := " >> termParser
678
+ let pattern := letPatDecl[0]
679
+ getPatternVarsEx pattern
680
+
681
+ def getLetEqnsDeclVars (letEqnsDecl : Syntax) : Array Var :=
682
+ assert! letEqnsDecl.isOfKind ``Parser.Term.letEqnsDecl
683
+ -- def letIdLhs : Parser := letId >> many (ppSpace >> letIdBinder) >> optType
684
+ -- def letEqnsDecl := leading_parser letIdLhs >> matchAlts
685
+ getLetIdVars letEqnsDecl[0]
686
+
687
+ def getLetDeclVars (letDecl : Syntax) : TermElabM (Array Var) := do
688
+ -- def letDecl := leading_parser letIdDecl <|> letPatDecl <|> letEqnsDecl
689
+ let arg := letDecl[0]
690
+ if arg.getKind == ``Parser.Term.letIdDecl then
691
+ return getLetIdDeclVars arg
692
+ else if arg.getKind == ``Parser.Term.letPatDecl then
693
+ getLetPatDeclVars arg
694
+ else if arg.getKind == ``Parser.Term.letEqnsDecl then
695
+ return getLetEqnsDeclVars arg
696
+ else
697
+ throwError "unexpected kind of let declaration"
698
+
699
+ def getDoLetVars (doLet : Syntax) : TermElabM (Array Var) :=
700
+ -- leading_parser "let " >> optional "mut " >> letDecl
701
+ getLetDeclVars doLet[2]
702
+
703
+ def getDoHaveVars (doHave : Syntax) : TermElabM (Array Var) :=
704
+ -- leading_parser "have" >> letDecl
705
+ getLetDeclVars doHave[1]
706
+
707
+ def getDoLetRecVars (doLetRec : Syntax) : TermElabM (Array Var) := do
708
+ -- letRecDecls is an array of `(group (optional attributes >> letDecl))`
709
+ let letRecDecls := doLetRec[1][0].getSepArgs
710
+ let letDecls := letRecDecls.map fun p => p[2]
711
+ let mut allVars := #[]
712
+ for letDecl in letDecls do
713
+ let vars ← getLetDeclVars letDecl
714
+ allVars := allVars ++ vars
715
+ return allVars
716
+
717
+ -- ident >> optType >> leftArrow >> termParser
718
+ def getDoIdDeclVar (doIdDecl : Syntax) : Var :=
719
+ doIdDecl[0]
720
+
721
+ -- termParser >> leftArrow >> termParser >> optional (" | " >> termParser)
722
+ def getDoPatDeclVars (doPatDecl : Syntax) : TermElabM (Array Var) := do
723
+ let pattern := doPatDecl[0]
724
+ getPatternVarsEx pattern
725
+
726
+ -- leading_parser "let " >> optional "mut " >> (doIdDecl <|> doPatDecl)
727
+ def getDoLetArrowVars (doLetArrow : Syntax) : TermElabM (Array Var) := do
728
+ let decl := doLetArrow[2]
729
+ if decl.getKind == ``Parser.Term.doIdDecl then
730
+ return #[getDoIdDeclVar decl]
731
+ else if decl.getKind == ``Parser.Term.doPatDecl then
732
+ getDoPatDeclVars decl
733
+ else
734
+ throwError "unexpected kind of `do` declaration"
735
+
736
+ def getDoReassignVars (doReassign : Syntax) : TermElabM (Array Var) := do
737
+ let arg := doReassign[0]
738
+ if arg.getKind == ``Parser.Term.letIdDecl then
739
+ return getLetIdDeclVars arg
740
+ else if arg.getKind == ``Parser.Term.letPatDecl then
741
+ getLetPatDeclVars arg
742
+ else
743
+ throwError "unexpected kind of reassignment"
744
+
745
+ def mkDoSeq (doElems : Array Syntax) : Syntax :=
746
+ mkNode `Lean.Parser.Term.doSeqIndent #[mkNullNode <| doElems.map fun doElem => mkNullNode #[doElem, mkNullNode]]
747
+
748
+ /--
749
+ If the given syntax is a `doIf`, return an equivalent `doIf` that has an `else` but no `else if`s or `if let`s. -/
750
+ private def expandDoIf? (stx : Syntax) : MacroM (Option Syntax) := match stx with
751
+ | `(doElem|if $_:doIfProp then $_ else $_) => pure none
752
+ | `(doElem|if $cond:doIfCond then $t $[else if $conds:doIfCond then $ts]* $[else $e?]?) => withRef stx do
753
+ let mut e := e?.getD (← `(doSeq|pure PUnit.unit))
754
+ let mut eIsSeq := true
755
+ for (cond, t) in Array.zip (conds.reverse.push cond) (ts.reverse.push t) do
756
+ e ← if eIsSeq then pure e else `(doSeq|$e:doElem)
757
+ e ← match cond with
758
+ | `(doIfCond|let $pat := $d) => `(doElem| match $d:term with | $pat:term => $t | _ => $e)
759
+ | `(doIfCond|let $pat ← $d) => `(doElem| match ← $d with | $pat:term => $t | _ => $e)
760
+ | `(doIfCond|$cond:doIfProp) => `(doElem| if $cond:doIfProp then $t else $e)
761
+ | _ => `(doElem| if $(Syntax.missing) then $t else $e)
762
+ eIsSeq := false
763
+ return some e
764
+ | _ => pure none
765
+
766
+ /--
767
+ If the given syntax is a `doLetExpr` or `doLetMetaExpr`, return an equivalent `doIf` that has an `else` but no `else if`s or `if let`s. -/
768
+ private def expandDoLetExpr? (stx : Syntax) (doElems : List Syntax) : MacroM (Option Syntax) := match stx with
769
+ | `(doElem| let_expr $pat:matchExprPat := $discr:term | $elseBranch:doSeq) =>
770
+ return some (← `(doElem| match_expr (meta := false) $discr:term with
771
+ | $pat:matchExprPat => $(mkDoSeq doElems.toArray)
772
+ | _ => $elseBranch))
773
+ | `(doElem| let_expr $pat:matchExprPat ← $discr:term | $elseBranch:doSeq) =>
774
+ return some (← `(doElem| match_expr $discr:term with
775
+ | $pat:matchExprPat => $(mkDoSeq doElems.toArray)
776
+ | _ => $elseBranch))
777
+ | _ => return none
778
+
779
+ structure DoIfView where
780
+ ref : Syntax
781
+ optIdent : Syntax
782
+ cond : Syntax
783
+ thenBranch : Syntax
784
+ elseBranch : Syntax
785
+
786
+ /-- This method assumes `expandDoIf?` is not applicable. -/
787
+ private def mkDoIfView (doIf : Syntax) : DoIfView := {
788
+ ref := doIf
789
+ optIdent := doIf[1][0]
790
+ cond := doIf[1][1]
791
+ thenBranch := doIf[3]
792
+ elseBranch := doIf[5][1]
793
+ }
794
+
795
+ /--
796
+ We use `MProd` instead of `Prod` to group values when expanding the
797
+ `do` notation. `MProd` is a universe monomorphic product.
798
+ The motivation is to generate simpler universe constraints in code
799
+ that was not written by the user.
800
+ Note that we are not restricting the macro power since the
801
+ `Bind.bind` combinator already forces values computed by monadic
802
+ actions to be in the same universe.
803
+ -/
804
+ private def mkTuple (elems : Array Syntax) : MacroM Syntax := do
805
+ if elems.size = 0 then
806
+ mkUnit
807
+ else if h : elems.size = 1 then
808
+ return elems[0]
809
+ else
810
+ elems.extract 0 (elems.size - 1) |>.foldrM (init := elems.back!) fun elem tuple =>
811
+ ``(MProd.mk $elem $tuple)
812
+
813
+ /-- Return `some action` if `doElem` is a `doExpr <action>`-/
814
+ def isDoExpr? (doElem : Syntax) : Option Syntax :=
815
+ if doElem.getKind == ``Parser.Term.doExpr then
816
+ some doElem[0]
817
+ else
818
+ none
819
+
820
+ /--
821
+ Given `uvars := #[a_1, ..., a_n, a_{n+1}]` construct term
822
+ ```
823
+ let a_1 := x.1
824
+ let x := x.2
825
+ let a_2 := x.1
826
+ let x := x.2
827
+ ...
828
+ let a_n := x.1
829
+ let a_{n+1} := x.2
830
+ body
831
+ ```
832
+ Special cases
833
+ - `uvars := #[]` => `body`
834
+ - `uvars := #[a]` => `let a := x; body`
835
+
836
+
837
+ We use this method when expanding the `for-in` notation.
838
+ -/
839
+ private def destructTuple (uvars : Array Var) (x : Syntax) (body : Syntax) : MacroM Syntax := do
840
+ if uvars.size = 0 then
841
+ return body
842
+ else if h : uvars.size = 1 then
843
+ `(let $(uvars[0]):ident := $x; $body)
844
+ else
845
+ destruct uvars.toList x body
846
+ where
847
+ destruct (as : List Var) (x : Syntax) (body : Syntax) : MacroM Syntax := do
848
+ match as with
849
+ | [a, b] => `(let $a:ident := $x.1; let $b:ident := $x.2; $body)
850
+ | a :: as => withFreshMacroScope do
851
+ let rest ← destruct as (← `(x)) body
852
+ `(let $a:ident := $x.1; let x := $x.2; $rest)
853
+ | _ => unreachable!
854
+
855
+ /-!
856
+ The procedure `ToTerm.run` converts a `CodeBlock` into a `Syntax` term.
857
+ We use this method to convert
858
+ 1- The `CodeBlock` for a root `do ...` term into a `Syntax` term. This kind of
859
+ `CodeBlock` never contains `break` nor `continue`. Moreover, the collection
860
+ of updated variables is not packed into the result.
861
+ Thus, we have two kinds of exit points
862
+ - `Code.action e` which is converted into `e`
863
+ - `Code.return _ e` which is converted into `pure e`
864
+
865
+ We use `Kind.regular` for this case.
866
+
867
+ 2- The `CodeBlock` for `b` at `for x in xs do b`. In this case, we need to generate
868
+ a `Syntax` term representing a function for the `xs.forIn` combinator.
869
+
870
+ a) If `b` contain a `Code.return _ a` exit point. The generated `Syntax` term
871
+ has type `m (ForInStep (Option Ξ± Γ— Οƒ))`, where `a : Ξ±`, and the `Οƒ` is the type
872
+ of the tuple of variables reassigned by `b`.
873
+ We use `Kind.forInWithReturn` for this case
874
+
875
+ b) If `b` does not contain a `Code.return _ a` exit point. Then, the generated
876
+ `Syntax` term has type `m (ForInStep Οƒ)`.
877
+ We use `Kind.forIn` for this case.
878
+
879
+ 3- The `CodeBlock` `c` for a `do` sequence nested in a monadic combinator (e.g., `MonadExcept.tryCatch`).
880
+
881
+ The generated `Syntax` term for `c` must inform whether `c` "exited" using `Code.action`, `Code.return`,
882
+ `Code.break` or `Code.continue`. We use the auxiliary types `DoResult`s for storing this information.
883
+ For example, the auxiliary type `DoResultPBC Ξ± Οƒ` is used for a code block that exits with `Code.action`,
884
+ **and** `Code.break`/`Code.continue`, `Ξ±` is the type of values produced by the exit `action`, and
885
+ `Οƒ` is the type of the tuple of reassigned variables.
886
+ The type `DoResult Ξ± Ξ² Οƒ` is usedf for code blocks that exit with
887
+ `Code.action`, `Code.return`, **and** `Code.break`/`Code.continue`, `Ξ²` is the type of the returned values.
888
+ We don't use `DoResult Ξ± Ξ² Οƒ` for all cases because:
889
+
890
+ a) The elaborator would not be able to infer all type parameters without extra annotations. For example,
891
+ if the code block does not contain `Code.return _ _`, the elaborator will not be able to infer `Ξ²`.
892
+
893
+ b) We need to pattern match on the result produced by the combinator (e.g., `MonadExcept.tryCatch`),
894
+ but we don't want to consider "unreachable" cases.
895
+
896
+ We do not distinguish between cases that contain `break`, but not `continue`, and vice versa.
897
+
898
+ When listing all cases, we use `a` to indicate the code block contains `Code.action _`, `r` for `Code.return _ _`,
899
+ and `b/c` for a code block that contains `Code.break _` or `Code.continue _`.
900
+
901
+ - `a`: `Kind.regular`, type `m (Ξ± Γ— Οƒ)`
902
+
903
+ - `r`: `Kind.regular`, type `m (Ξ± Γ— Οƒ)`
904
+ Note that the code that pattern matches on the result will behave differently in this case.
905
+ It produces `return a` for this case, and `pure a` for the previous one.
906
+
907
+ - `b/c`: `Kind.nestedBC`, type `m (DoResultBC Οƒ)`
908
+
909
+ - `a` and `r`: `Kind.nestedPR`, type `m (DoResultPR Ξ± Ξ² Οƒ)`
910
+
911
+ - `a` and `bc`: `Kind.nestedSBC`, type `m (DoResultSBC Ξ± Οƒ)`
912
+
913
+ - `r` and `bc`: `Kind.nestedSBC`, type `m (DoResultSBC Ξ± Οƒ)`
914
+ Again the code that pattern matches on the result will behave differently in this case and
915
+ the previous one. It produces `return a` for the constructor `DoResultSPR.pureReturn a u` for
916
+ this case, and `pure a` for the previous case.
917
+
918
+ - `a`, `r`, `b/c`: `Kind.nestedPRBC`, type type `m (DoResultPRBC Ξ± Ξ² Οƒ)`
919
+
920
+ Here is the recipe for adding new combinators with nested `do`s.
921
+ Example: suppose we want to support `repeat doSeq`. Assuming we have `repeat : m Ξ± β†’ m Ξ±`
922
+ 1- Convert `doSeq` into `codeBlock : CodeBlock`
923
+ 2- Create term `term` using `mkNestedTerm code m uvars a r bc` where
924
+ `code` is `codeBlock.code`, `uvars` is an array containing `codeBlock.uvars`,
925
+ `m` is a `Syntax` representing the Monad, and
926
+ `a` is true if `code` contains `Code.action _`,
927
+ `r` is true if `code` contains `Code.return _ _`,
928
+ `bc` is true if `code` contains `Code.break _` or `Code.continue _`.
929
+
930
+ Remark: for combinators such as `repeat` that take a single `doSeq`, all
931
+ arguments, but `m`, are extracted from `codeBlock`.
932
+ 3- Create the term `repeat $term`
933
+ 4- and then, convert it into a `doSeq` using `matchNestedTermResult ref (repeat $term) uvsar a r bc`
934
+
935
+ -/
936
+
937
+ /--
938
+ Helper method for annotating `term` with the raw syntax `ref`.
939
+ We use this method to implement finer-grained term infos for `do`-blocks.
940
+
941
+ We use `withRef term` to make sure the synthetic position for the `with_annotate_term` is equal
942
+ to the one for `term`. This is important for producing error messages when there is a type mismatch.
943
+ Consider the following example:
944
+ ```
945
+ opaque f : IO Nat
946
+
947
+ def g : IO String := do
948
+ f
949
+ ```
950
+ There is at type mismatch at `f`, but it is detected when elaborating the expanded term
951
+ containing the `with_annotate_term .. f`. The current `getRef` when this `annotate` is invoked
952
+ is not necessarily `f`. Actually, it is the whole `do`-block. By using `withRef` we ensure
953
+ the synthetic position for the `with_annotate_term ..` is equal to `term`.
954
+ Recall that synthetic positions are used when generating error messages.
955
+ -/
956
+ def annotate [Monad m] [MonadRef m] [MonadQuotation m] (ref : Syntax) (term : Syntax) : m Syntax :=
957
+ withRef term <| `(with_annotate_term $ref $term)
958
+
959
+ namespace ToTerm
960
+
961
+ inductive Kind where
962
+ | regular
963
+ | forIn
964
+ | forInWithReturn
965
+ | nestedBC
966
+ | nestedPR
967
+ | nestedSBC
968
+ | nestedPRBC
969
+
970
+ instance : Inhabited Kind := ⟨Kind.regular⟩
971
+
972
+ def Kind.isRegular : Kind β†’ Bool
973
+ | .regular => true
974
+ | _ => false
975
+
976
+ structure Context where
977
+ /-- Syntax to reference the monad associated with the do notation. -/
978
+ m : Syntax
979
+ /-- Syntax to reference the result of the monadic computation performed by the do notation. -/
980
+ returnType : Syntax
981
+ uvars : Array Var
982
+ kind : Kind
983
+
984
+ abbrev M := ReaderT Context MacroM
985
+
986
+ def mkUVarTuple : M Syntax := do
987
+ let ctx ← read
988
+ mkTuple ctx.uvars
989
+
990
+ def returnToTerm (val : Syntax) : M Syntax := do
991
+ let ctx ← read
992
+ let u ← mkUVarTuple
993
+ match ctx.kind with
994
+ | .regular => if ctx.uvars.isEmpty then ``(Pure.pure $val) else ``(Pure.pure (MProd.mk $val $u))
995
+ | .forIn => ``(Pure.pure (ForInStep.done $u))
996
+ | .forInWithReturn => ``(Pure.pure (ForInStep.done (MProd.mk (some $val) $u)))
997
+ | .nestedBC => unreachable!
998
+ | .nestedPR => ``(Pure.pure (DoResultPR.Β«returnΒ» $val $u))
999
+ | .nestedSBC => ``(Pure.pure (DoResultSBC.Β«pureReturnΒ» $val $u))
1000
+ | .nestedPRBC => ``(Pure.pure (DoResultPRBC.Β«returnΒ» $val $u))
1001
+
1002
+ def continueToTerm : M Syntax := do
1003
+ let ctx ← read
1004
+ let u ← mkUVarTuple
1005
+ match ctx.kind with
1006
+ | .regular => unreachable!
1007
+ | .forIn => ``(Pure.pure (ForInStep.yield $u))
1008
+ | .forInWithReturn => ``(Pure.pure (ForInStep.yield (MProd.mk none $u)))
1009
+ | .nestedBC => ``(Pure.pure (DoResultBC.Β«continueΒ» $u))
1010
+ | .nestedPR => unreachable!
1011
+ | .nestedSBC => ``(Pure.pure (DoResultSBC.Β«continueΒ» $u))
1012
+ | .nestedPRBC => ``(Pure.pure (DoResultPRBC.Β«continueΒ» $u))
1013
+
1014
+ def breakToTerm : M Syntax := do
1015
+ let ctx ← read
1016
+ let u ← mkUVarTuple
1017
+ match ctx.kind with
1018
+ | .regular => unreachable!
1019
+ | .forIn => ``(Pure.pure (ForInStep.done $u))
1020
+ | .forInWithReturn => ``(Pure.pure (ForInStep.done (MProd.mk none $u)))
1021
+ | .nestedBC => ``(Pure.pure (DoResultBC.Β«breakΒ» $u))
1022
+ | .nestedPR => unreachable!
1023
+ | .nestedSBC => ``(Pure.pure (DoResultSBC.Β«breakΒ» $u))
1024
+ | .nestedPRBC => ``(Pure.pure (DoResultPRBC.Β«breakΒ» $u))
1025
+
1026
+ def actionTerminalToTerm (action : Syntax) : M Syntax := withRef action <| withFreshMacroScope do
1027
+ let ctx ← read
1028
+ let u ← mkUVarTuple
1029
+ match ctx.kind with
1030
+ | .regular => if ctx.uvars.isEmpty then pure action else ``(Bind.bind $action fun y => Pure.pure (MProd.mk y $u))
1031
+ | .forIn => ``(Bind.bind $action fun (_ : PUnit) => Pure.pure (ForInStep.yield $u))
1032
+ | .forInWithReturn => ``(Bind.bind $action fun (_ : PUnit) => Pure.pure (ForInStep.yield (MProd.mk none $u)))
1033
+ | .nestedBC => unreachable!
1034
+ | .nestedPR => ``(Bind.bind $action fun y => (Pure.pure (DoResultPR.Β«pureΒ» y $u)))
1035
+ | .nestedSBC => ``(Bind.bind $action fun y => (Pure.pure (DoResultSBC.Β«pureReturnΒ» y $u)))
1036
+ | .nestedPRBC => ``(Bind.bind $action fun y => (Pure.pure (DoResultPRBC.Β«pureΒ» y $u)))
1037
+
1038
+ def seqToTerm (action : Syntax) (k : Syntax) : M Syntax := withRef action <| withFreshMacroScope do
1039
+ if action.getKind == ``Parser.Term.doDbgTrace then
1040
+ let msg := action[1]
1041
+ `(dbg_trace $msg; $k)
1042
+ else if action.getKind == ``Parser.Term.doAssert then
1043
+ let cond := action[1]
1044
+ `(assert! $cond; $k)
1045
+ else if action.getKind == ``Parser.Term.doDebugAssert then
1046
+ let cond := action[1]
1047
+ `(debugAssert| debug_assert! $cond; $k)
1048
+ else
1049
+ let action ← withRef action ``(($action : $((←read).m) PUnit))
1050
+ ``(Bind.bind $action (fun (_ : PUnit) => $k))
1051
+
1052
+ def declToTerm (decl : Syntax) (k : Syntax) : M Syntax := withRef decl <| withFreshMacroScope do
1053
+ let kind := decl.getKind
1054
+ if kind == ``Parser.Term.doLet then
1055
+ let letDecl := decl[2]
1056
+ `(let $letDecl:letDecl; $k)
1057
+ else if kind == ``Parser.Term.doLetRec then
1058
+ let letRecToken := decl[0]
1059
+ let letRecDecls := decl[1]
1060
+ return mkNode ``Parser.Term.letrec #[letRecToken, letRecDecls, mkNullNode, k]
1061
+ else if kind == ``Parser.Term.doLetArrow then
1062
+ let arg := decl[2]
1063
+ if arg.getKind == ``Parser.Term.doIdDecl then
1064
+ let id := arg[0]
1065
+ let type := expandOptType id arg[1]
1066
+ let doElem := arg[3]
1067
+ -- `doElem` must be a `doExpr action`. See `doLetArrowToCode`
1068
+ match isDoExpr? doElem with
1069
+ | some action =>
1070
+ let action ← withRef action `(($action : $((← read).m) $type))
1071
+ ``(Bind.bind $action (fun ($id:ident : $type) => $k))
1072
+ | none => Macro.throwErrorAt decl "unexpected kind of `do` declaration"
1073
+ else
1074
+ Macro.throwErrorAt decl "unexpected kind of `do` declaration"
1075
+ else if kind == ``Parser.Term.doHave then
1076
+ -- The `have` term is of the form `"have " >> letDecl >> optSemicolon termParser`
1077
+ let args := decl.getArgs
1078
+ let args := args ++ #[mkNullNode /- optional ';' -/, k]
1079
+ return mkNode `Lean.Parser.Term.Β«haveΒ» args
1080
+ else
1081
+ Macro.throwErrorAt decl "unexpected kind of `do` declaration"
1082
+
1083
+ def reassignToTerm (reassign : Syntax) (k : Syntax) : MacroM Syntax := withRef reassign <| withFreshMacroScope do
1084
+ match reassign with
1085
+ | `(doElem| $x:ident := $rhs) => `(let $x:ident := ensure_type_of% $x $(quote "invalid reassignment, value") $rhs; $k)
1086
+ | `(doElem| $e:term := $rhs) => `(let $e:term := ensure_type_of% $e $(quote "invalid reassignment, value") $rhs; $k)
1087
+ | _ =>
1088
+ -- Note that `doReassignArrow` is expanded by `doReassignArrowToCode
1089
+ Macro.throwErrorAt reassign "unexpected kind of `do` reassignment"
1090
+
1091
+ def mkIte (optIdent : Syntax) (cond : Syntax) (thenBranch : Syntax) (elseBranch : Syntax) : MacroM Syntax := do
1092
+ if optIdent.isNone then
1093
+ ``(if $cond then $thenBranch else $elseBranch)
1094
+ else
1095
+ let h := optIdent[0]
1096
+ ``(if $h:ident : $cond then $thenBranch else $elseBranch)
1097
+
1098
+ def mkJoinPoint (j : Name) (ps : Array (Syntax Γ— Bool)) (body : Syntax) (k : Syntax) : M Syntax := withRef body <| withFreshMacroScope do
1099
+ let pTypes ← ps.mapM fun ⟨id, useTypeOf⟩ => do if useTypeOf then `(type_of% $id) else `(_)
1100
+ let ps := ps.map (Β·.1)
1101
+ /-
1102
+ We use `let_delayed` instead of `let` for joinpoints to make sure `$k` is elaborated before `$body`.
1103
+ By elaborating `$k` first, we "learn" more about `$body`'s type.
1104
+ For example, consider the following example `do` expression
1105
+ ```
1106
+ def f (x : Nat) : IO Unit := do
1107
+ if x > 0 then
1108
+ IO.println "x is not zero" -- Error is here
1109
+ IO.mkRef true
1110
+ ```
1111
+ it is expanded into
1112
+ ```
1113
+ def f (x : Nat) : IO Unit := do
1114
+ let jp (u : Unit) : IO _ :=
1115
+ IO.mkRef true;
1116
+ if x > 0 then
1117
+ IO.println "not zero"
1118
+ jp ()
1119
+ else
1120
+ jp ()
1121
+ ```
1122
+ If we use the regular `let` instead of `let_delayed`, the joinpoint `jp` will be elaborated and its type will be inferred to be `Unit β†’ IO (IO.Ref Bool)`.
1123
+ Then, we get a typing error at `jp ()`. By using `let_delayed`, we first elaborate `if x > 0 ...` and learn that `jp` has type `Unit β†’ IO Unit`.
1124
+ Then, we get the expected type mismatch error at `IO.mkRef true`. -/
1125
+ `(let_delayed $(← mkIdentFromRef j):ident $[($ps : $pTypes)]* : $((← read).m) _ := $body; $k)
1126
+
1127
+ def mkJmp (ref : Syntax) (j : Name) (args : Array Syntax) : Syntax :=
1128
+ Syntax.mkApp (mkIdentFrom ref j) args
1129
+
1130
+ partial def toTerm (c : Code) : M Syntax := do
1131
+ let term ← go c
1132
+ if let some ref := c.getRef? then
1133
+ annotate ref term
1134
+ else
1135
+ return term
1136
+ where
1137
+ go (c : Code) : M Syntax := do
1138
+ match c with
1139
+ | .return ref val => withRef ref <| returnToTerm val
1140
+ | .continue ref => withRef ref continueToTerm
1141
+ | .break ref => withRef ref breakToTerm
1142
+ | .action e => actionTerminalToTerm e
1143
+ | .joinpoint j ps b k => mkJoinPoint j ps (← toTerm b) (← toTerm k)
1144
+ | .jmp ref j args => return mkJmp ref j args
1145
+ | .decl _ stx k => declToTerm stx (← toTerm k)
1146
+ | .reassign _ stx k => reassignToTerm stx (← toTerm k)
1147
+ | .seq stx k => seqToTerm stx (← toTerm k)
1148
+ | .ite ref _ o c t e => withRef ref <| do mkIte o c (← toTerm t) (← toTerm e)
1149
+ | .match ref genParam discrs optMotive alts =>
1150
+ let mut termAlts := #[]
1151
+ for alt in alts do
1152
+ let rhs ← toTerm alt.rhs
1153
+ let termAlt := mkNode ``Parser.Term.matchAlt #[mkAtomFrom alt.ref "|", mkNullNode #[alt.patterns], mkAtomFrom alt.ref "=>", rhs]
1154
+ termAlts := termAlts.push termAlt
1155
+ let termMatchAlts := mkNode ``Parser.Term.matchAlts #[mkNullNode termAlts]
1156
+ return mkNode ``Parser.Term.Β«matchΒ» #[mkAtomFrom ref "match", genParam, optMotive, discrs, mkAtomFrom ref "with", termMatchAlts]
1157
+ | .matchExpr ref Β«metaΒ» d alts elseBranch => withFreshMacroScope do
1158
+ let d' ← `(discr)
1159
+ let mut termAlts := #[]
1160
+ for alt in alts do
1161
+ let rhs ← `(($(← toTerm alt.rhs) : $((← read).m) _))
1162
+ let optVar := if let some var := alt.var? then mkNullNode #[var, mkAtomFrom var "@"] else mkNullNode #[]
1163
+ let pat := mkNode ``Parser.Term.matchExprPat #[optVar, alt.funName, mkNullNode alt.pvars]
1164
+ let termAlt := mkNode ``Parser.Term.matchExprAlt #[mkAtomFrom alt.ref "|", pat, mkAtomFrom alt.ref "=>", rhs]
1165
+ termAlts := termAlts.push termAlt
1166
+ let elseBranch := mkNode ``Parser.Term.matchExprElseAlt #[mkAtomFrom ref "|", mkHole ref, mkAtomFrom ref "=>", (← toTerm elseBranch)]
1167
+ let termMatchExprAlts := mkNode ``Parser.Term.matchExprAlts #[mkNullNode termAlts, elseBranch]
1168
+ let body := mkNode ``Parser.Term.matchExpr #[mkAtomFrom ref "match_expr", d', mkAtomFrom ref "with", termMatchExprAlts]
1169
+ if Β«metaΒ» then
1170
+ `(Bind.bind (instantiateMVarsIfMVarApp $d) fun discr => $body)
1171
+ else
1172
+ `(let discr := $d; $body)
1173
+
1174
+ def run (code : Code) (m : Syntax) (returnType : Syntax) (uvars : Array Var := #[]) (kind := Kind.regular) : MacroM Syntax :=
1175
+ toTerm code { m, returnType, kind, uvars }
1176
+
1177
+ /-- Given
1178
+ - `a` is true if the code block has a `Code.action _` exit point
1179
+ - `r` is true if the code block has a `Code.return _ _` exit point
1180
+ - `bc` is true if the code block has a `Code.break _` or `Code.continue _` exit point
1181
+
1182
+ generate Kind. See comment at the beginning of the `ToTerm` namespace. -/
1183
+ def mkNestedKind (a r bc : Bool) : Kind :=
1184
+ match a, r, bc with
1185
+ | true, false, false => .regular
1186
+ | false, true, false => .regular
1187
+ | false, false, true => .nestedBC
1188
+ | true, true, false => .nestedPR
1189
+ | true, false, true => .nestedSBC
1190
+ | false, true, true => .nestedSBC
1191
+ | true, true, true => .nestedPRBC
1192
+ | false, false, false => unreachable!
1193
+
1194
+ def mkNestedTerm (code : Code) (m : Syntax) (returnType : Syntax) (uvars : Array Var) (a r bc : Bool) : MacroM Syntax := do
1195
+ ToTerm.run code m returnType uvars (mkNestedKind a r bc)
1196
+
1197
+ /-- Given a term `term` produced by `ToTerm.run`, pattern match on its result.
1198
+ See comment at the beginning of the `ToTerm` namespace.
1199
+
1200
+ - `a` is true if the code block has a `Code.action _` exit point
1201
+ - `r` is true if the code block has a `Code.return _ _` exit point
1202
+ - `bc` is true if the code block has a `Code.break _` or `Code.continue _` exit point
1203
+
1204
+ The result is a sequence of `doElem` -/
1205
+ def matchNestedTermResult (term : Syntax) (uvars : Array Var) (a r bc : Bool) : MacroM (List Syntax) := do
1206
+ let toDoElems (auxDo : Syntax) : List Syntax := getDoSeqElems (getDoSeq auxDo)
1207
+ let u ← mkTuple uvars
1208
+ match a, r, bc with
1209
+ | true, false, false =>
1210
+ if uvars.isEmpty then
1211
+ return toDoElems (← `(do $term:term))
1212
+ else
1213
+ return toDoElems (← `(do let r ← $term:term; $u:term := r.2; pure r.1))
1214
+ | false, true, false =>
1215
+ if uvars.isEmpty then
1216
+ return toDoElems (← `(do let r ← $term:term; return r))
1217
+ else
1218
+ return toDoElems (← `(do let r ← $term:term; $u:term := r.2; return r.1))
1219
+ | false, false, true => toDoElems <$>
1220
+ `(do let r ← $term:term;
1221
+ match r with
1222
+ | .break u => $u:term := u; break
1223
+ | .continue u => $u:term := u; continue)
1224
+ | true, true, false => toDoElems <$>
1225
+ `(do let r ← $term:term;
1226
+ match r with
1227
+ | .pure a u => $u:term := u; pure a
1228
+ | .return b u => $u:term := u; return b)
1229
+ | true, false, true => toDoElems <$>
1230
+ `(do let r ← $term:term;
1231
+ match r with
1232
+ | .pureReturn a u => $u:term := u; pure a
1233
+ | .break u => $u:term := u; break
1234
+ | .continue u => $u:term := u; continue)
1235
+ | false, true, true => toDoElems <$>
1236
+ `(do let r ← $term:term;
1237
+ match r with
1238
+ | .pureReturn a u => $u:term := u; return a
1239
+ | .break u => $u:term := u; break
1240
+ | .continue u => $u:term := u; continue)
1241
+ | true, true, true => toDoElems <$>
1242
+ `(do let r ← $term:term;
1243
+ match r with
1244
+ | .pure a u => $u:term := u; pure a
1245
+ | .return a u => $u:term := u; return a
1246
+ | .break u => $u:term := u; break
1247
+ | .continue u => $u:term := u; continue)
1248
+ | false, false, false => unreachable!
1249
+
1250
+ end ToTerm
1251
+
1252
+ def isMutableLet (doElem : Syntax) : Bool :=
1253
+ let kind := doElem.getKind
1254
+ (kind == ``doLetArrow || kind == ``doLet || kind == ``doLetElse)
1255
+ &&
1256
+ !doElem[1].isNone
1257
+
1258
+ namespace ToCodeBlock
1259
+
1260
+ structure Context where
1261
+ ref : Syntax
1262
+ /-- Syntax representing the monad associated with the do notation. -/
1263
+ m : Syntax
1264
+ /-- Syntax to reference the result of the monadic computation performed by the do notation. -/
1265
+ returnType : Syntax
1266
+ mutableVars : VarSet := {}
1267
+ insideFor : Bool := false
1268
+
1269
+ abbrev M := ReaderT Context TermElabM
1270
+
1271
+ def withNewMutableVars {Ξ±} (newVars : Array Var) (mutable : Bool) (x : M Ξ±) : M Ξ± :=
1272
+ withReader (fun ctx => if mutable then { ctx with mutableVars := insertVars ctx.mutableVars newVars } else ctx) x
1273
+
1274
+ def checkReassignable (xs : Array Var) : M Unit := do
1275
+ let throwInvalidReassignment (x : Name) : M Unit :=
1276
+ throwError "`{x.simpMacroScopes}` cannot be mutated, only variables declared using `let mut` can be mutated. If you did not intend to mutate but define `{x.simpMacroScopes}`, consider using `let {x.simpMacroScopes}` instead"
1277
+ let ctx ← read
1278
+ for x in xs do
1279
+ unless ctx.mutableVars.contains x.getId do
1280
+ throwInvalidReassignment x.getId
1281
+
1282
+ def checkNotShadowingMutable (xs : Array Var) : M Unit := do
1283
+ let throwInvalidShadowing (x : Name) : M Unit :=
1284
+ throwError "mutable variable `{x.simpMacroScopes}` cannot be shadowed"
1285
+ let ctx ← read
1286
+ for x in xs do
1287
+ if ctx.mutableVars.contains x.getId then
1288
+ withRef x <| throwInvalidShadowing x.getId
1289
+
1290
+ def withFor {Ξ±} (x : M Ξ±) : M Ξ± :=
1291
+ withReader (fun ctx => { ctx with insideFor := true }) x
1292
+
1293
+ structure ToForInTermResult where
1294
+ uvars : Array Var
1295
+ term : Syntax
1296
+
1297
+ def mkForInBody (_ : Syntax) (forInBody : CodeBlock) : M ToForInTermResult := do
1298
+ let ctx ← read
1299
+ let uvars := forInBody.uvars
1300
+ let uvars := varSetToArray uvars
1301
+ let term ← liftMacroM <| ToTerm.run forInBody.code ctx.m ctx.returnType uvars (if hasReturn forInBody.code then ToTerm.Kind.forInWithReturn else ToTerm.Kind.forIn)
1302
+ return ⟨uvars, term⟩
1303
+
1304
+ def ensureInsideFor : M Unit :=
1305
+ unless (← read).insideFor do
1306
+ throwError "invalid `do` element, it must be inside `for`"
1307
+
1308
+ def ensureEOS (doElems : List Syntax) : M Unit :=
1309
+ unless doElems.isEmpty do
1310
+ throwError "must be last element in a `do` sequence"
1311
+
1312
+ variable (baseId : Name) in
1313
+ private partial def expandLiftMethodAux (inQuot : Bool) (inBinder : Bool) : Syntax β†’ StateT (List Syntax) M Syntax
1314
+ | stx@(Syntax.node i k args) =>
1315
+ if k == choiceKind then do
1316
+ -- choice node: check that lifts are consistent
1317
+ let alts ← stx.getArgs.mapM (expandLiftMethodAux inQuot inBinder Β· |>.run [])
1318
+ let (_, lifts) := alts[0]!
1319
+ unless alts.all (Β·.2 == lifts) do
1320
+ throwErrorAt stx "cannot lift `(<- ...)` over inconsistent syntax variants, consider lifting out the binding manually"
1321
+ modify (Β· ++ lifts)
1322
+ return .node i k (alts.map (Β·.1))
1323
+ else if liftMethodDelimiter k then
1324
+ return stx
1325
+ -- For `pure` if-then-else, we only lift `(<- ...)` occurring in the condition.
1326
+ else if h : args.size >= 2 ∧ (k == ``termDepIfThenElse || k == ``termIfThenElse) then do
1327
+ let inAntiquot := stx.isAntiquot && !stx.isEscapedAntiquot
1328
+ let arg1 ← expandLiftMethodAux (inQuot && !inAntiquot || stx.isQuot) inBinder args[1]
1329
+ let args := args.set! 1 arg1
1330
+ return Syntax.node i k args
1331
+ else if k == ``Parser.Term.liftMethod && !inQuot then withFreshMacroScope do
1332
+ if inBinder then
1333
+ throwErrorAt stx "cannot lift `(<- ...)` over a binder, this error usually happens when you are trying to lift a method nested in a `fun`, `let`, or `match`-alternative, and it can often be fixed by adding a missing `do`"
1334
+ let term := args[1]!
1335
+ let term ← expandLiftMethodAux inQuot inBinder term
1336
+ -- keep name deterministic across choice branches
1337
+ let id ← mkIdentFromRef (.num baseId (← get).length)
1338
+ let auxDoElem : Syntax ← `(doElem| let $id:ident ← $term:term)
1339
+ modify fun s => s ++ [auxDoElem]
1340
+ return id
1341
+ else do
1342
+ let inAntiquot := stx.isAntiquot && !stx.isEscapedAntiquot
1343
+ let inBinder := inBinder || (!inQuot && liftMethodForbiddenBinder stx)
1344
+ let args ← args.mapM (expandLiftMethodAux (inQuot && !inAntiquot || stx.isQuot) inBinder)
1345
+ return Syntax.node i k args
1346
+ | stx => return stx
1347
+
1348
+ def expandLiftMethod (doElem : Syntax) : M (List Syntax Γ— Syntax) := do
1349
+ if !hasLiftMethod doElem then
1350
+ return ([], doElem)
1351
+ else
1352
+ let baseId ← withFreshMacroScope (MonadQuotation.addMacroScope `__do_lift)
1353
+ let (doElem, doElemsNew) ← (expandLiftMethodAux baseId false false doElem).run []
1354
+ return (doElemsNew, doElem)
1355
+
1356
+ def checkLetArrowRHS (doElem : Syntax) : M Unit := do
1357
+ let kind := doElem.getKind
1358
+ if kind == ``Parser.Term.doLetArrow ||
1359
+ kind == ``Parser.Term.doLet ||
1360
+ kind == ``Parser.Term.doLetRec ||
1361
+ kind == ``Parser.Term.doHave ||
1362
+ kind == ``Parser.Term.doReassign ||
1363
+ kind == ``Parser.Term.doReassignArrow then
1364
+ throwErrorAt doElem "invalid kind of value `{kind}` in an assignment"
1365
+
1366
+ /-- Generate `CodeBlock` for `doReturn` which is of the form
1367
+ ```
1368
+ "return " >> optional termParser
1369
+ ```
1370
+ `doElems` is only used for sanity checking. -/
1371
+ def doReturnToCode (doReturn : Syntax) (doElems: List Syntax) : M CodeBlock := withRef doReturn do
1372
+ ensureEOS doElems
1373
+ let argOpt := doReturn[1]
1374
+ let arg ← if argOpt.isNone then liftMacroM mkUnit else pure argOpt[0]
1375
+ return mkReturn (← getRef) arg
1376
+
1377
+ structure Catch where
1378
+ x : Syntax
1379
+ optType : Syntax
1380
+ codeBlock : CodeBlock
1381
+
1382
+ def getTryCatchUpdatedVars (tryCode : CodeBlock) (catches : Array Catch) (finallyCode? : Option CodeBlock) : VarSet :=
1383
+ let ws := tryCode.uvars
1384
+ let ws := catches.foldl (init := ws) fun ws alt => union alt.codeBlock.uvars ws
1385
+ let ws := match finallyCode? with
1386
+ | none => ws
1387
+ | some c => union c.uvars ws
1388
+ ws
1389
+
1390
+ def tryCatchPred (tryCode : CodeBlock) (catches : Array Catch) (finallyCode? : Option CodeBlock) (p : Code β†’ Bool) : Bool :=
1391
+ p tryCode.code ||
1392
+ catches.any (fun Β«catchΒ» => p Β«catchΒ».codeBlock.code) ||
1393
+ match finallyCode? with
1394
+ | none => false
1395
+ | some finallyCode => p finallyCode.code
1396
+
1397
+ mutual
1398
+ /-- "Concatenate" `c` with `doSeqToCode doElems` -/
1399
+ partial def concatWith (c : CodeBlock) (doElems : List Syntax) : M CodeBlock :=
1400
+ match doElems with
1401
+ | [] => pure c
1402
+ | nextDoElem :: _ => do
1403
+ let k ← doSeqToCode doElems
1404
+ let ref := nextDoElem
1405
+ concat c ref none k
1406
+
1407
+ /-- Generate `CodeBlock` for `doLetArrow; doElems`
1408
+ `doLetArrow` is of the form
1409
+ ```
1410
+ "let " >> optional "mut " >> (doIdDecl <|> doPatDecl)
1411
+ ```
1412
+ where
1413
+ ```
1414
+ def doIdDecl := leading_parser ident >> optType >> leftArrow >> doElemParser
1415
+ def doPatDecl := leading_parser termParser >> leftArrow >> doElemParser >> optional (" | " >> doSeq)
1416
+ ```
1417
+ -/
1418
+ partial def doLetArrowToCode (doLetArrow : Syntax) (doElems : List Syntax) : M CodeBlock := do
1419
+ let decl := doLetArrow[2]
1420
+ if decl.getKind == ``Parser.Term.doIdDecl then
1421
+ let y := decl[0]
1422
+ checkNotShadowingMutable #[y]
1423
+ let doElem := decl[3]
1424
+ let k ← withNewMutableVars #[y] (isMutableLet doLetArrow) (doSeqToCode doElems)
1425
+ match isDoExpr? doElem with
1426
+ | some _ => return mkVarDeclCore #[y] doLetArrow k
1427
+ | none =>
1428
+ checkLetArrowRHS doElem
1429
+ let c ← doSeqToCode [doElem]
1430
+ match doElems with
1431
+ | [] => pure c
1432
+ | kRef::_ => concat c kRef y k
1433
+ else if decl.getKind == ``Parser.Term.doPatDecl then
1434
+ let pattern := decl[0]
1435
+ let doElem := decl[2]
1436
+ let optElse := decl[3]
1437
+ if optElse.isNone then withFreshMacroScope do
1438
+ let auxDo ← if isMutableLet doLetArrow then
1439
+ `(do let%$doLetArrow __discr ← $doElem; let%$doLetArrow mut $pattern:term := __discr)
1440
+ else
1441
+ `(do let%$doLetArrow __discr ← $doElem; let%$doLetArrow $pattern:term := __discr)
1442
+ doSeqToCode <| getDoSeqElems (getDoSeq auxDo) ++ doElems
1443
+ else
1444
+ let contSeq ← if isMutableLet doLetArrow then
1445
+ let vars ← (← getPatternVarsEx pattern).mapM fun var => `(doElem| let mut $var := $var)
1446
+ pure (vars ++ doElems.toArray)
1447
+ else
1448
+ pure doElems.toArray
1449
+ let contSeq := mkDoSeq contSeq
1450
+ let elseSeq := optElse[1]
1451
+ let auxDo ← `(do let%$doLetArrow __discr ← $doElem; match%$doLetArrow __discr with | $pattern:term => $contSeq | _ => $elseSeq)
1452
+ doSeqToCode <| getDoSeqElems (getDoSeq auxDo)
1453
+ else
1454
+ throwError "unexpected kind of `do` declaration"
1455
+
1456
+ partial def doLetElseToCode (doLetElse : Syntax) (doElems : List Syntax) : M CodeBlock := do
1457
+ -- "let " >> optional "mut " >> termParser >> " := " >> termParser >> checkColGt >> " | " >> doSeq
1458
+ let pattern := doLetElse[2]
1459
+ let val := doLetElse[4]
1460
+ let elseSeq := doLetElse[6]
1461
+ let contSeq ← if isMutableLet doLetElse then
1462
+ let vars ← (← getPatternVarsEx pattern).mapM fun var => `(doElem| let mut $var := $var)
1463
+ pure (vars ++ doElems.toArray)
1464
+ else
1465
+ pure doElems.toArray
1466
+ let contSeq := mkDoSeq contSeq
1467
+ let auxDo ← `(do match $val:term with | $pattern:term => $contSeq | _ => $elseSeq)
1468
+ doSeqToCode <| getDoSeqElems (getDoSeq auxDo)
1469
+
1470
+ /-- Generate `CodeBlock` for `doReassignArrow; doElems`
1471
+ `doReassignArrow` is of the form
1472
+ ```
1473
+ (doIdDecl <|> doPatDecl)
1474
+ ```
1475
+ -/
1476
+ partial def doReassignArrowToCode (doReassignArrow : Syntax) (doElems : List Syntax) : M CodeBlock := do
1477
+ let decl := doReassignArrow[0]
1478
+ if decl.getKind == ``Parser.Term.doIdDecl then
1479
+ let doElem := decl[3]
1480
+ let y := decl[0]
1481
+ let auxDo ← `(do let r ← $doElem; $y:ident := r)
1482
+ doSeqToCode <| getDoSeqElems (getDoSeq auxDo) ++ doElems
1483
+ else if decl.getKind == ``Parser.Term.doPatDecl then
1484
+ let pattern := decl[0]
1485
+ let doElem := decl[2]
1486
+ let optElse := decl[3]
1487
+ if optElse.isNone then withFreshMacroScope do
1488
+ let auxDo ← `(do let __discr ← $doElem; $pattern:term := __discr)
1489
+ doSeqToCode <| getDoSeqElems (getDoSeq auxDo) ++ doElems
1490
+ else
1491
+ throwError "reassignment with `|` (i.e., \"else clause\") is not currently supported"
1492
+ else
1493
+ throwError "unexpected kind of `do` reassignment"
1494
+
1495
+ /-- Generate `CodeBlock` for `doIf; doElems`
1496
+ `doIf` is of the form
1497
+ ```
1498
+ "if " >> optIdent >> termParser >> " then " >> doSeq
1499
+ >> many (group (try (group (" else " >> " if ")) >> optIdent >> termParser >> " then " >> doSeq))
1500
+ >> optional (" else " >> doSeq)
1501
+ ``` -/
1502
+ partial def doIfToCode (doIf : Syntax) (doElems : List Syntax) : M CodeBlock := do
1503
+ let view := mkDoIfView doIf
1504
+ let thenBranch ← doSeqToCode (getDoSeqElems view.thenBranch)
1505
+ let elseBranch ← doSeqToCode (getDoSeqElems view.elseBranch)
1506
+ let ite ← mkIte view.ref view.optIdent view.cond thenBranch elseBranch
1507
+ concatWith ite doElems
1508
+
1509
+ /-- Generate `CodeBlock` for `doUnless; doElems`
1510
+ `doUnless` is of the form
1511
+ ```
1512
+ "unless " >> termParser >> "do " >> doSeq
1513
+ ``` -/
1514
+ partial def doUnlessToCode (doUnless : Syntax) (doElems : List Syntax) : M CodeBlock := withRef doUnless do
1515
+ let cond := doUnless[1]
1516
+ let doSeq := doUnless[3]
1517
+ let body ← doSeqToCode (getDoSeqElems doSeq)
1518
+ let unlessCode ← liftMacroM <| mkUnless cond body
1519
+ concatWith unlessCode doElems
1520
+
1521
+ /-- Generate `CodeBlock` for `doFor; doElems`
1522
+ `doFor` is of the form
1523
+ ```
1524
+ def doForDecl := leading_parser termParser >> " in " >> withForbidden "do" termParser
1525
+ def doFor := leading_parser "for " >> sepBy1 doForDecl ", " >> "do " >> doSeq
1526
+ ```
1527
+ -/
1528
+ partial def doForToCode (doFor : Syntax) (doElems : List Syntax) : M CodeBlock := do
1529
+ let doForDecls := doFor[1].getSepArgs
1530
+ if h : doForDecls.size > 1 then
1531
+ /-
1532
+ Expand
1533
+ ```
1534
+ for x in xs, y in ys do
1535
+ body
1536
+ ```
1537
+ into
1538
+ ```
1539
+ let s := toStream ys
1540
+ for x in xs do
1541
+ match Stream.next? s with
1542
+ | none => break
1543
+ | some (y, s') =>
1544
+ s := s'
1545
+ body
1546
+ ```
1547
+ -/
1548
+ -- Extract second element
1549
+ let doForDecl := doForDecls[1]!
1550
+ unless doForDecl[0].isNone do
1551
+ throwErrorAt doForDecl[0] "the proof annotation here has not been implemented yet"
1552
+ let y := doForDecl[1]
1553
+ let ys := doForDecl[3]
1554
+ let doForDecls := doForDecls.eraseIdx 1
1555
+ let body := doFor[3]
1556
+ withFreshMacroScope do
1557
+ /- Recall that `@` (explicit) disables `coeAtOutParam`.
1558
+ We used `@` at `Stream` functions to make sure `resultIsOutParamSupport` is not used. -/
1559
+ let toStreamApp ← withRef ys `(@toStream _ _ _ $ys)
1560
+ let auxDo ←
1561
+ `(do let mut s := $toStreamApp:term
1562
+ for $doForDecls:doForDecl,* do
1563
+ match @Stream.next? _ _ _ s with
1564
+ | none => break
1565
+ | some ($y, s') =>
1566
+ s := s'
1567
+ do $body)
1568
+ doSeqToCode (getDoSeqElems (getDoSeq auxDo) ++ doElems)
1569
+ else withRef doFor do
1570
+ let h? := if doForDecls[0]![0].isNone then none else some doForDecls[0]![0][0]
1571
+ let x := doForDecls[0]![1]
1572
+ withRef x <| checkNotShadowingMutable (← getPatternVarsEx x)
1573
+ let xs := doForDecls[0]![3]
1574
+ let forElems := getDoSeqElems doFor[3]
1575
+ let forInBodyCodeBlock ← withFor (doSeqToCode forElems)
1576
+ let ⟨uvars, forInBody⟩ ← mkForInBody x forInBodyCodeBlock
1577
+ let ctx ← read
1578
+ -- semantic no-op that replaces the `uvars`' position information (which all point inside the loop)
1579
+ -- with that of the respective mutable declarations outside the loop, which allows the language
1580
+ -- server to identify them as conceptually identical variables
1581
+ let uvars := uvars.map fun v => ctx.mutableVars.findD v.getId v
1582
+ let uvarsTuple ← liftMacroM do mkTuple uvars
1583
+ if hasReturn forInBodyCodeBlock.code then
1584
+ let forInBody ← liftMacroM <| destructTuple uvars (← `(r)) forInBody
1585
+ let optType ← `(Option $((← read).returnType))
1586
+ let forInTerm ← if let some h := h? then
1587
+ annotate doFor
1588
+ (← `(for_in'% $(xs) (MProd.mk (none : $optType) $uvarsTuple) fun $x $h (r : MProd $optType _) => let r := r.2; $forInBody))
1589
+ else
1590
+ annotate doFor
1591
+ (← `(for_in% $(xs) (MProd.mk (none : $optType) $uvarsTuple) fun $x (r : MProd $optType _) => let r := r.2; $forInBody))
1592
+ let auxDo ← `(do let r ← $forInTerm:term;
1593
+ $uvarsTuple:term := r.2;
1594
+ match r.1 with
1595
+ | none => Pure.pure (ensure_expected_type% "type mismatch, `for`" PUnit.unit)
1596
+ | some a => return ensure_expected_type% "type mismatch, `for`" a)
1597
+ doSeqToCode (getDoSeqElems (getDoSeq auxDo) ++ doElems)
1598
+ else
1599
+ let forInBody ← liftMacroM <| destructTuple uvars (← `(r)) forInBody
1600
+ let forInTerm ← if let some h := h? then
1601
+ annotate doFor (← `(for_in'% $(xs) $uvarsTuple fun $x $h r => $forInBody))
1602
+ else
1603
+ annotate doFor (← `(for_in% $(xs) $uvarsTuple fun $x r => $forInBody))
1604
+ if doElems.isEmpty then
1605
+ let auxDo ← `(do let r ← $forInTerm:term;
1606
+ $uvarsTuple:term := r;
1607
+ Pure.pure (ensure_expected_type% "type mismatch, `for`" PUnit.unit))
1608
+ doSeqToCode <| getDoSeqElems (getDoSeq auxDo)
1609
+ else
1610
+ let auxDo ← `(do let r ← $forInTerm:term; $uvarsTuple:term := r)
1611
+ doSeqToCode <| getDoSeqElems (getDoSeq auxDo) ++ doElems
1612
+
1613
+ /-- Generate `CodeBlock` for `doMatch; doElems` -/
1614
+ partial def doMatchToCode (doMatch : Syntax) (doElems: List Syntax) : M CodeBlock := do
1615
+ let ref := doMatch
1616
+ let genParam := doMatch[1]
1617
+ let optMotive := doMatch[2]
1618
+ let discrs := doMatch[3]
1619
+ let matchAlts := doMatch[5][0].getArgs -- Array of `doMatchAlt`
1620
+ let matchAlts ← matchAlts.foldlM (init := #[]) fun result matchAlt => return result ++ (← liftMacroM <| expandMatchAlt matchAlt)
1621
+ let alts ← matchAlts.mapM fun matchAlt => do
1622
+ let patterns := matchAlt[1][0]
1623
+ let vars ← getPatternsVarsEx patterns.getSepArgs
1624
+ withRef patterns <| checkNotShadowingMutable vars
1625
+ let rhs := matchAlt[3]
1626
+ let rhs ← doSeqToCode (getDoSeqElems rhs)
1627
+ pure { ref := matchAlt, vars := vars, patterns := patterns, rhs := rhs : Alt CodeBlock }
1628
+ let matchCode ← mkMatch ref genParam discrs optMotive alts
1629
+ concatWith matchCode doElems
1630
+
1631
+ /-- Generate `CodeBlock` for `doMatchExpr; doElems` -/
1632
+ partial def doMatchExprToCode (doMatchExpr : Syntax) (doElems: List Syntax) : M CodeBlock := do
1633
+ let ref := doMatchExpr
1634
+ let Β«metaΒ» := doMatchExpr[1].isNone
1635
+ let discr := doMatchExpr[2]
1636
+ let alts := doMatchExpr[4][0].getArgs -- Array of `doMatchExprAlt`
1637
+ let alts ← alts.mapM fun alt => do
1638
+ let pat := alt[1]
1639
+ let var? := if pat[0].isNone then none else some pat[0][0]
1640
+ let funName := pat[1]
1641
+ let pvars := pat[2].getArgs
1642
+ let rhs := alt[3]
1643
+ let rhs ← doSeqToCode (getDoSeqElems rhs)
1644
+ pure { ref, var?, funName, pvars, rhs }
1645
+ let elseBranch ← doSeqToCode (getDoSeqElems doMatchExpr[4][1][3])
1646
+ let matchCode ← mkMatchExpr ref Β«metaΒ» discr alts elseBranch
1647
+ concatWith matchCode doElems
1648
+
1649
+ /--
1650
+ Generate `CodeBlock` for `doTry; doElems`
1651
+ ```
1652
+ def doTry := leading_parser "try " >> doSeq >> many (doCatch <|> doCatchMatch) >> optional doFinally
1653
+ def doCatch := leading_parser "catch " >> binderIdent >> optional (":" >> termParser) >> darrow >> doSeq
1654
+ def doCatchMatch := leading_parser "catch " >> doMatchAlts
1655
+ def doFinally := leading_parser "finally " >> doSeq
1656
+ ```
1657
+ -/
1658
+ partial def doTryToCode (doTry : Syntax) (doElems: List Syntax) : M CodeBlock := do
1659
+ let tryCode ← doSeqToCode (getDoSeqElems doTry[1])
1660
+ let optFinally := doTry[3]
1661
+ let catches ← doTry[2].getArgs.mapM fun catchStx : Syntax => do
1662
+ if catchStx.getKind == ``Parser.Term.doCatch then
1663
+ let x := catchStx[1]
1664
+ if x.isIdent then
1665
+ withRef x <| checkNotShadowingMutable #[x]
1666
+ let optType := catchStx[2]
1667
+ let c ← doSeqToCode (getDoSeqElems catchStx[4])
1668
+ return { x := x, optType := optType, codeBlock := c : Catch }
1669
+ else if catchStx.getKind == ``Parser.Term.doCatchMatch then
1670
+ let matchAlts := catchStx[1]
1671
+ let x ← `(ex)
1672
+ let auxDo ← `(do match ex with $matchAlts)
1673
+ let c ← doSeqToCode (getDoSeqElems (getDoSeq auxDo))
1674
+ return { x := x, codeBlock := c, optType := mkNullNode : Catch }
1675
+ else
1676
+ throwError "unexpected kind of `catch`"
1677
+ let finallyCode? ← if optFinally.isNone then pure none else some <$> doSeqToCode (getDoSeqElems optFinally[0][1])
1678
+ if catches.isEmpty && finallyCode?.isNone then
1679
+ throwError "invalid `try`, it must have a `catch` or `finally`"
1680
+ let ctx ← read
1681
+ let ws := getTryCatchUpdatedVars tryCode catches finallyCode?
1682
+ let uvars := varSetToArray ws
1683
+ let a := tryCatchPred tryCode catches finallyCode? hasTerminalAction
1684
+ let r := tryCatchPred tryCode catches finallyCode? hasReturn
1685
+ let bc := tryCatchPred tryCode catches finallyCode? hasBreakContinue
1686
+ let toTerm (codeBlock : CodeBlock) : M Syntax := do
1687
+ let codeBlock ← liftM $ extendUpdatedVars codeBlock ws
1688
+ liftMacroM <| ToTerm.mkNestedTerm codeBlock.code ctx.m ctx.returnType uvars a r bc
1689
+ let term ← toTerm tryCode
1690
+ let term ← catches.foldlM (init := term) fun term Β«catchΒ» => do
1691
+ let catchTerm ← toTerm Β«catchΒ».codeBlock
1692
+ if catch.optType.isNone then
1693
+ annotate doTry (← ``(MonadExcept.tryCatch $term (fun $(Β«catchΒ».x):ident => $catchTerm)))
1694
+ else
1695
+ let type := Β«catchΒ».optType[1]
1696
+ annotate doTry (← ``(tryCatchThe $type $term (fun $(Β«catchΒ».x):ident => $catchTerm)))
1697
+ let term ← match finallyCode? with
1698
+ | none => pure term
1699
+ | some finallyCode => withRef optFinally do
1700
+ unless finallyCode.uvars.isEmpty do
1701
+ throwError "`finally` currently does not support reassignments"
1702
+ if hasBreakContinueReturn finallyCode.code then
1703
+ throwError "`finally` currently does `return`, `break`, nor `continue`"
1704
+ let finallyTerm ← liftMacroM <| ToTerm.run finallyCode.code ctx.m ctx.returnType {} ToTerm.Kind.regular
1705
+ annotate doTry (← ``(tryFinally $term $finallyTerm))
1706
+ let doElemsNew ← liftMacroM <| ToTerm.matchNestedTermResult term uvars a r bc
1707
+ doSeqToCode (doElemsNew ++ doElems)
1708
+
1709
+ partial def doSeqToCode : List Syntax β†’ M CodeBlock
1710
+ | [] => do liftMacroM mkPureUnitAction
1711
+ | doElem::doElems => withIncRecDepth <| withRef doElem do
1712
+ checkSystem "`do`-expander"
1713
+ match (← liftMacroM <| expandMacro? doElem) with
1714
+ | some doElem => doSeqToCode (doElem::doElems)
1715
+ | none =>
1716
+ match (← liftMacroM <| expandDoIf? doElem) with
1717
+ | some doElem => doSeqToCode (doElem::doElems)
1718
+ | none =>
1719
+ match (← liftMacroM <| expandDoLetExpr? doElem doElems) with
1720
+ | some doElem => doSeqToCode [doElem]
1721
+ | none =>
1722
+ let (liftedDoElems, doElem) ← expandLiftMethod doElem
1723
+ if !liftedDoElems.isEmpty then
1724
+ doSeqToCode (liftedDoElems ++ [doElem] ++ doElems)
1725
+ else
1726
+ let ref := doElem
1727
+ let k := doElem.getKind
1728
+ if k == ``Parser.Term.doLet then
1729
+ let vars ← getDoLetVars doElem
1730
+ checkNotShadowingMutable vars
1731
+ mkVarDeclCore vars doElem <$> withNewMutableVars vars (isMutableLet doElem) (doSeqToCode doElems)
1732
+ else if k == ``Parser.Term.doHave then
1733
+ let vars ← getDoHaveVars doElem
1734
+ checkNotShadowingMutable vars
1735
+ mkVarDeclCore vars doElem <$> (doSeqToCode doElems)
1736
+ else if k == ``Parser.Term.doLetRec then
1737
+ let vars ← getDoLetRecVars doElem
1738
+ checkNotShadowingMutable vars
1739
+ mkVarDeclCore vars doElem <$> (doSeqToCode doElems)
1740
+ else if k == ``Parser.Term.doReassign then
1741
+ let vars ← getDoReassignVars doElem
1742
+ checkReassignable vars
1743
+ let k ← doSeqToCode doElems
1744
+ mkReassignCore vars doElem k
1745
+ else if k == ``Parser.Term.doLetArrow then
1746
+ doLetArrowToCode doElem doElems
1747
+ else if k == ``Parser.Term.doLetElse then
1748
+ doLetElseToCode doElem doElems
1749
+ else if k == ``Parser.Term.doReassignArrow then
1750
+ doReassignArrowToCode doElem doElems
1751
+ else if k == ``Parser.Term.doIf then
1752
+ doIfToCode doElem doElems
1753
+ else if k == ``Parser.Term.doUnless then
1754
+ doUnlessToCode doElem doElems
1755
+ else if k == ``Parser.Term.doFor then withFreshMacroScope do
1756
+ doForToCode doElem doElems
1757
+ else if k == ``Parser.Term.doMatch then
1758
+ doMatchToCode doElem doElems
1759
+ else if k == ``Parser.Term.doMatchExpr then
1760
+ doMatchExprToCode doElem doElems
1761
+ else if k == ``Parser.Term.doTry then
1762
+ doTryToCode doElem doElems
1763
+ else if k == ``Parser.Term.doBreak then
1764
+ ensureInsideFor
1765
+ ensureEOS doElems
1766
+ return mkBreak ref
1767
+ else if k == ``Parser.Term.doContinue then
1768
+ ensureInsideFor
1769
+ ensureEOS doElems
1770
+ return mkContinue ref
1771
+ else if k == ``Parser.Term.doReturn then
1772
+ doReturnToCode doElem doElems
1773
+ else if k == ``Parser.Term.doDbgTrace then
1774
+ return mkSeq doElem (← doSeqToCode doElems)
1775
+ else if k == ``Parser.Term.doAssert then
1776
+ return mkSeq doElem (← doSeqToCode doElems)
1777
+ else if k == ``Parser.Term.doDebugAssert then
1778
+ return mkSeq doElem (← doSeqToCode doElems)
1779
+ else if k == ``Parser.Term.doNested then
1780
+ let nestedDoSeq := doElem[1]
1781
+ doSeqToCode (getDoSeqElems nestedDoSeq ++ doElems)
1782
+ else if k == ``Parser.Term.doExpr then
1783
+ let term := doElem[0]
1784
+ if doElems.isEmpty then
1785
+ return mkTerminalAction term
1786
+ else
1787
+ return mkSeq term (← doSeqToCode doElems)
1788
+ else
1789
+ throwError "unexpected do-element of kind {doElem.getKind}:\n{doElem}"
1790
+ end
1791
+
1792
+ def run (doStx : Syntax) (m : Syntax) (returnType : Syntax) : TermElabM CodeBlock :=
1793
+ (doSeqToCode <| getDoSeqElems <| getDoSeq doStx).run { ref := doStx, m, returnType }
1794
+
1795
+ end ToCodeBlock
1796
+
1797
+ @[builtin_term_elab Β«doΒ»] def elabDo : TermElab := fun stx expectedType? => do
1798
+ tryPostponeIfNoneOrMVar expectedType?
1799
+ let bindInfo ← extractBind expectedType?
1800
+ let m ← Term.exprToSyntax bindInfo.m
1801
+ let returnType ← Term.exprToSyntax bindInfo.returnType
1802
+ let codeBlock ← ToCodeBlock.run stx m returnType
1803
+ let stxNew ← liftMacroM <| ToTerm.run codeBlock.code m returnType
1804
+ trace[Elab.do] stxNew
1805
+ withMacroExpansion stx stxNew <| elabTermEnsuringType stxNew bindInfo.expectedType
1806
+
1807
+ end Do
1808
+
1809
+ builtin_initialize registerTraceClass `Elab.do
1810
+
1811
+ private def toDoElem (newKind : SyntaxNodeKind) : Macro := fun stx => do
1812
+ let stx := stx.setKind newKind
1813
+ withRef stx `(do $stx:doElem)
1814
+
1815
+ @[builtin_macro Lean.Parser.Term.termFor]
1816
+ def expandTermFor : Macro := toDoElem ``Parser.Term.doFor
1817
+
1818
+ @[builtin_macro Lean.Parser.Term.termTry]
1819
+ def expandTermTry : Macro := toDoElem ``Parser.Term.doTry
1820
+
1821
+ @[builtin_macro Lean.Parser.Term.termUnless]
1822
+ def expandTermUnless : Macro := toDoElem ``Parser.Term.doUnless
1823
+
1824
+ @[builtin_macro Lean.Parser.Term.termReturn]
1825
+ def expandTermReturn : Macro := toDoElem ``Parser.Term.doReturn
1826
+
1827
+ end Lean.Elab.Term
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/ElabRules.lean ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Elab.MacroArgUtil
8
+ import Lean.Elab.AuxDef
9
+
10
+ namespace Lean.Elab.Command
11
+ open Lean.Syntax
12
+ open Lean.Parser.Term hiding macroArg
13
+ open Lean.Parser.Command
14
+
15
+ def elabElabRulesAux (doc? : Option (TSyntax ``docComment))
16
+ (attrs? : Option (TSepArray ``attrInstance ",")) (attrKind : TSyntax ``attrKind)
17
+ (k : SyntaxNodeKind) (cat? expty? : Option (Ident)) (alts : Array (TSyntax ``matchAlt)) :
18
+ CommandElabM Syntax := do
19
+ let alts ← alts.mapM fun (alt : TSyntax ``matchAlt) => match alt with
20
+ | `(matchAltExpr| | $pats,* => $rhs) => do
21
+ let pat := pats.elemsAndSeps[0]!
22
+ if !pat.isQuot then
23
+ throwUnsupportedSyntax
24
+ let quoted := getQuotContent pat
25
+ let k' := quoted.getKind
26
+ if checkRuleKind k' k then
27
+ pure alt
28
+ else if k' == choiceKind then
29
+ match quoted.getArgs.find? fun quotAlt => checkRuleKind quotAlt.getKind k with
30
+ | none => throwErrorAt alt "invalid elab_rules alternative, expected syntax node kind '{k}'"
31
+ | some quoted =>
32
+ let pat := pat.setArg 1 quoted
33
+ let pats := ⟨pats.elemsAndSeps.set! 0 pat⟩
34
+ `(matchAltExpr| | $pats,* => $rhs)
35
+ else
36
+ throwErrorAt alt "invalid elab_rules alternative, unexpected syntax node kind '{k'}'"
37
+ | _ => throwUnsupportedSyntax
38
+ let catName ← match cat?, expty? with
39
+ | some cat, _ => pure cat.getId
40
+ | _, some _ => pure `term
41
+ -- TODO: infer category from quotation kind, possibly even kind of quoted syntax?
42
+ | _, _ => throwError "invalid elab_rules command, specify category using `elab_rules : <cat> ...`"
43
+ let mkAttrs (kind : Name) : CommandElabM (TSyntaxArray ``attrInstance) := do
44
+ let attr ← `(attrInstance| $attrKind:attrKind $(mkIdent kind):ident $(← mkIdentFromRef k):ident)
45
+ pure <| match attrs? with
46
+ | some attrs => attrs.getElems.push attr
47
+ | none => #[attr]
48
+ if let some expId := expty? then
49
+ if catName == `term then
50
+ `($[$doc?:docComment]? @[$(← mkAttrs `term_elab),*]
51
+ aux_def elabRules $(mkIdent k) : Lean.Elab.Term.TermElab :=
52
+ fun stx expectedType? => Lean.Elab.Term.withExpectedType expectedType? fun $expId => match stx with
53
+ $alts:matchAlt* | _ => no_error_if_unused% throwUnsupportedSyntax)
54
+ else
55
+ throwErrorAt expId "syntax category '{catName}' does not support expected type specification"
56
+ else if catName == `term then
57
+ `($[$doc?:docComment]? @[$(← mkAttrs `term_elab),*]
58
+ aux_def elabRules $(mkIdent k) : Lean.Elab.Term.TermElab :=
59
+ fun stx _ => match stx with
60
+ $alts:matchAlt* | _ => no_error_if_unused% throwUnsupportedSyntax)
61
+ else if catName == `command then
62
+ `($[$doc?:docComment]? @[$(← mkAttrs `command_elab),*]
63
+ aux_def elabRules $(mkIdent k) : Lean.Elab.Command.CommandElab :=
64
+ fun $alts:matchAlt* | _ => no_error_if_unused% throwUnsupportedSyntax)
65
+ else if catName == `tactic || catName == `conv then
66
+ `($[$doc?:docComment]? @[$(← mkAttrs `tactic),*]
67
+ aux_def elabRules $(mkIdent k) : Lean.Elab.Tactic.Tactic :=
68
+ fun $alts:matchAlt* | _ => no_error_if_unused% throwUnsupportedSyntax)
69
+ else
70
+ -- We considered making the command extensible and support new user-defined categories. We think it is unnecessary.
71
+ -- If users want this feature, they add their own `elab_rules` macro that uses this one as a fallback.
72
+ throwError "unsupported syntax category '{catName}'"
73
+
74
+ @[builtin_command_elab Β«elab_rulesΒ»] def elabElabRules : CommandElab :=
75
+ adaptExpander fun stx => match stx with
76
+ | `($[$doc?:docComment]? $[@[$attrs?,*]]? $attrKind:attrKind elab_rules $[: $cat?]? $[<= $expty?]? $alts:matchAlt*) =>
77
+ expandNoKindMacroRulesAux alts "elab_rules" fun kind? alts =>
78
+ `($[$doc?:docComment]? $[@[$attrs?,*]]? $attrKind:attrKind elab_rules $[(kind := $(mkIdent <$> kind?))]? $[: $cat?]? $[<= $expty?]? $alts:matchAlt*)
79
+ | `($[$doc?:docComment]? $[@[$attrs?,*]]? $attrKind:attrKind elab_rules (kind := $kind) $[: $cat?]? $[<= $expty?]? $alts:matchAlt*) =>
80
+ do elabElabRulesAux doc? attrs? attrKind (← resolveSyntaxKind kind.getId) cat? expty? alts
81
+ | _ => throwUnsupportedSyntax
82
+
83
+ @[builtin_command_elab Lean.Parser.Command.elab]
84
+ def elabElab : CommandElab
85
+ | `($[$doc?:docComment]? $[@[$attrs?,*]]? $attrKind:attrKind
86
+ elab%$tk$[:$prec?]? $[(name := $name?)]? $[(priority := $prio?)]? $args:macroArg* :
87
+ $cat $[<= $expectedType?]? => $rhs) => do
88
+ let prio ← liftMacroM <| evalOptPrio prio?
89
+ let (stxParts, patArgs) := (← args.mapM expandMacroArg).unzip
90
+ -- name
91
+ let name ← match name? with
92
+ | some name => pure name.getId
93
+ | none => addMacroScopeIfLocal (← liftMacroM <| mkNameFromParserSyntax cat.getId (mkNullNode stxParts)) attrKind
94
+ let nameId := name?.getD (mkIdentFrom tk name (canonical := true))
95
+ let pat := ⟨mkNode ((← getCurrNamespace) ++ name) patArgs⟩
96
+ elabCommand <|← `(
97
+ $[$doc?:docComment]? $[@[$attrs?,*]]? $attrKind:attrKind
98
+ syntax%$tk$[:$prec?]? (name := $nameId) (priority := $(quote prio):num) $[$stxParts]* : $cat
99
+ $[$doc?:docComment]? elab_rules : $cat $[<= $expectedType?]? | `($pat) => $rhs)
100
+ | _ => throwUnsupportedSyntax
101
+
102
+ end Lean.Elab.Command
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/ErrorExplanation.lean ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Joseph Rotella
5
+ -/
6
+ prelude
7
+ import Lean.ErrorExplanation
8
+ import Lean.Meta.Eval
9
+ import Lean.Elab.Term
10
+ import Lean.Elab.Command
11
+ import Lean.Widget.UserWidget
12
+
13
+ namespace Lean.Elab.ErrorExplanation
14
+
15
+ open Meta Parser Term
16
+
17
+ -- We cannot import the definitions needed for this attribute in `Lean.Log`, so we instead add it
18
+ -- here
19
+ attribute [builtin_widget_module] Lean.errorDescriptionWidget
20
+
21
+ def expandNamedErrorMacro : Macro
22
+ | `(throwNamedErrorMacro| throwNamedError $id:ident $msg:interpolatedStr) =>
23
+ ``(Lean.throwNamedError $(quote id.getId) m! $msg)
24
+ | `(throwNamedErrorMacro| throwNamedError $id $msg:term) =>
25
+ ``(Lean.throwNamedError $(quote id.getId) $msg)
26
+ | `(throwNamedErrorAtMacro| throwNamedErrorAt $ref $id $msg:interpolatedStr) =>
27
+ ``(Lean.throwNamedErrorAt $ref $(quote id.getId) m! $msg)
28
+ | `(throwNamedErrorAtMacro| throwNamedErrorAt $ref $id $msg:term) =>
29
+ ``(Lean.throwNamedErrorAt $ref $(quote id.getId) $msg)
30
+ | `(logNamedErrorMacro| logNamedError $id $msg:interpolatedStr) =>
31
+ ``(Lean.logNamedError $(quote id.getId) m! $msg)
32
+ | `(logNamedErrorMacro| logNamedError $id $msg:term) =>
33
+ ``(Lean.logNamedError $(quote id.getId) $msg)
34
+ | `(logNamedErrorAtMacro| logNamedErrorAt $ref $id $msg:interpolatedStr) =>
35
+ ``(Lean.logNamedErrorAt $ref $(quote id.getId) m! $msg)
36
+ | `(logNamedErrorAtMacro| logNamedErrorAt $ref $id $msg:term) =>
37
+ ``(Lean.logNamedErrorAt $ref $(quote id.getId) $msg)
38
+ | `(logNamedWarningMacro| logNamedWarning $id $msg:interpolatedStr) =>
39
+ ``(Lean.logNamedWarning $(quote id.getId) m! $msg)
40
+ | `(logNamedWarningMacro| logNamedWarning $id $msg:term) =>
41
+ ``(Lean.logNamedWarning $(quote id.getId) $msg)
42
+ | `(logNamedWarningAtMacro| logNamedWarningAt $ref $id $msg:interpolatedStr) =>
43
+ ``(Lean.logNamedWarningAt $ref $(quote id.getId) m! $msg)
44
+ | `(logNamedWarningAtMacro| logNamedWarningAt $ref $id $msg:term) =>
45
+ ``(Lean.logNamedWarningAt $ref $(quote id.getId) $msg)
46
+ | _ => Macro.throwUnsupported
47
+
48
+ /--
49
+ Maps macro syntax categories to a pair of the module containing the declaration on which the macro
50
+ depends and the name of that declaration.
51
+ -/
52
+ private def macroDeclMap :=
53
+ Std.HashMap.ofList
54
+ [(``throwNamedErrorMacro, (`Lean.Exception, ``Lean.throwNamedError)),
55
+ (``throwNamedErrorAtMacro, (`Lean.Exception, ``Lean.throwNamedErrorAt)),
56
+ (``logNamedErrorMacro, (`Lean.Log, ``Lean.logNamedError)),
57
+ (``logNamedErrorAtMacro, (`Lean.Log, ``Lean.logNamedErrorAt)),
58
+ (``logNamedWarningMacro, (`Lean.Log, ``Lean.logNamedWarning)),
59
+ (``logNamedWarningAtMacro, (`Lean.Log, ``Lean.logNamedWarningAt))]
60
+
61
+ @[builtin_term_elab throwNamedErrorMacro, builtin_term_elab throwNamedErrorAtMacro,
62
+ builtin_term_elab logNamedErrorMacro, builtin_term_elab logNamedErrorAtMacro,
63
+ builtin_term_elab logNamedWarningMacro, builtin_term_elab logNamedWarningAtMacro]
64
+ def elabCheckedNamedError : TermElab := fun stx expType? => do
65
+ if let some (module, decl) := macroDeclMap.get? stx.getKind then
66
+ if !(← getEnv).contains decl then
67
+ throwError m!"The constant `{decl}` has not been imported" ++
68
+ .hint' m!"Add `import {module}` to this file's header to use this macro"
69
+ let (id, numArgsExpected) :=
70
+ if stx.isOfKind ``throwNamedErrorAtMacro || stx.isOfKind ``logNamedErrorAtMacro
71
+ || stx.isOfKind ``logNamedWarningAtMacro then
72
+ (stx[2], 5)
73
+ else
74
+ (stx[1], 4)
75
+ -- Remove the message term from the span. If we have a trailing `.`, we fail to parse the message
76
+ -- term and so leave `stx` unchanged. The in-progress identifier will always be the penultimate
77
+ -- argument of `span`.
78
+ let span := if stx.getNumArgs == numArgsExpected then
79
+ stx.setArgs (stx.getArgs[*...(stx.getNumArgs - 1)])
80
+ else
81
+ stx
82
+ let partialId := span[span.getNumArgs - 2]
83
+ addCompletionInfo <| CompletionInfo.errorName span partialId
84
+ let name := id.getId.eraseMacroScopes
85
+ pushInfoLeaf <| .ofErrorNameInfo { stx := id, errorName := name }
86
+ if let some explan := getErrorExplanationRaw? (← getEnv) name then
87
+ if let some removedVersion := explan.metadata.removedVersion? then
88
+ logWarningAt id m!"The error name `{name}` was removed in Lean version {removedVersion} and \
89
+ should not be used."
90
+ else
91
+ logErrorAt id m!"There is no explanation associated with the name `{name}`. \
92
+ Add an explanation of this error to the `Lean.ErrorExplanations` module."
93
+ let stx' ← liftMacroM <| expandNamedErrorMacro stx
94
+ elabTerm stx' expType?
95
+
96
+ open Command in
97
+ @[builtin_command_elab registerErrorExplanationStx] def elabRegisterErrorExplanation : CommandElab
98
+ | `(registerErrorExplanationStx| $docStx:docComment register_error_explanation%$cmd $id:ident $t:term) => withRef cmd do
99
+ unless (← getEnv).contains ``Lean.ErrorExplanation do
100
+ throwError "To use this command, add `import Lean.ErrorExplanation` to the header of this file"
101
+ let tp := mkConst ``ErrorExplanation.Metadata
102
+ let metadata ← runTermElabM <| fun _ => unsafe do
103
+ let e ← elabTerm t tp
104
+ if e.hasSyntheticSorry then throwAbortTerm
105
+ evalExpr ErrorExplanation.Metadata tp e
106
+ let name := id.getId
107
+ if name.isAnonymous then
108
+ throwErrorAt id "Invalid name for error explanation: `{id}`"
109
+ if name.hasMacroScopes then
110
+ -- Use `id` rather than `name` for nicer rendering
111
+ throwErrorAt id m!"Invalid name `{id}`: Error explanations cannot have inaccessible names. \
112
+ This error often occurs when an error explanation is generated using a macro."
113
+ if name.getNumParts != 2 then
114
+ throwErrorAt id m!"Invalid name `{name}`: Error explanation names must have two components"
115
+ ++ .note m!"The first component of an error explanation name identifies the package from \
116
+ which the error originates, and the second identifies the error itself."
117
+ validateDocComment docStx
118
+ let doc ← getDocStringText docStx
119
+ if errorExplanationExt.getState (← getEnv) |>.contains name then
120
+ throwErrorAt id m!"Cannot add explanation: An error explanation already exists for `{name}`"
121
+ if let .error (lineOffset, msg) := ErrorExplanation.processDoc doc then
122
+ let some range := docStx.raw[1].getRange? | throwError msg
123
+ let fileMap ← getFileMap
124
+ let ⟨startLine, _⟩ := fileMap.toPosition range.start
125
+ let errLine := startLine + lineOffset
126
+ let synth := Syntax.ofRange { start := fileMap.ofPosition ⟨errLine, 0⟩,
127
+ stop := fileMap.ofPosition ⟨errLine + 1, 0⟩ }
128
+ throwErrorAt synth msg
129
+ let (declLoc? : Option DeclarationLocation) ← do
130
+ let map ← getFileMap
131
+ let start := id.raw.getPos?.getD 0
132
+ let fin := id.raw.getTailPos?.getD start
133
+ pure <| some {
134
+ module := (← getMainModule)
135
+ range := .ofStringPositions map start fin
136
+ }
137
+ modifyEnv (errorExplanationExt.addEntry Β· (name, { metadata, doc, declLoc? }))
138
+ | _ => throwUnsupportedSyntax
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Eval.lean ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2022 Sebastian Ullrich. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Sebastian Ullrich
5
+ -/
6
+ prelude
7
+ import Lean.Meta.Eval
8
+ import Lean.Elab.SyntheticMVars
9
+
10
+ namespace Lean.Elab.Term
11
+ open Meta
12
+
13
+ unsafe def evalTerm (Ξ±) (type : Expr) (value : Syntax) (safety := DefinitionSafety.safe) : TermElabM Ξ± := withoutModifyingEnv do
14
+ let v ← elabTermEnsuringType value type
15
+ synthesizeSyntheticMVarsNoPostponing
16
+ let v ← instantiateMVars v
17
+ if (← logUnassignedUsingErrorInfos (← getMVars v)) then throwAbortTerm
18
+ evalExpr Ξ± type v safety
19
+
20
+ end Lean.Elab.Term
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Exception.lean ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2019 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.InternalExceptionId
8
+ import Lean.Exception
9
+
10
+ namespace Lean.Elab
11
+
12
+ builtin_initialize postponeExceptionId : InternalExceptionId ← registerInternalExceptionId `postpone
13
+ builtin_initialize unsupportedSyntaxExceptionId : InternalExceptionId ← registerInternalExceptionId `unsupportedSyntax
14
+ builtin_initialize abortCommandExceptionId : InternalExceptionId ← registerInternalExceptionId `abortCommandElab
15
+ builtin_initialize abortTermExceptionId : InternalExceptionId ← registerInternalExceptionId `abortTermElab
16
+ builtin_initialize abortTacticExceptionId : InternalExceptionId ← registerInternalExceptionId `abortTactic
17
+ builtin_initialize autoBoundImplicitExceptionId : InternalExceptionId ← registerInternalExceptionId `autoBoundImplicit
18
+
19
+ def throwPostpone [MonadExceptOf Exception m] : m Ξ± :=
20
+ throw $ Exception.internal postponeExceptionId
21
+
22
+ def throwUnsupportedSyntax [MonadExceptOf Exception m] : m Ξ± :=
23
+ throw $ Exception.internal unsupportedSyntaxExceptionId
24
+
25
+ def throwIllFormedSyntax [Monad m] [MonadError m] : m Ξ± :=
26
+ throwError "ill-formed syntax"
27
+
28
+ def throwAutoBoundImplicitLocal [MonadExceptOf Exception m] (n : Name) : m Ξ± :=
29
+ throw $ Exception.internal autoBoundImplicitExceptionId <| KVMap.empty.insert `localId n
30
+
31
+ def isAutoBoundImplicitLocalException? (ex : Exception) : Option Name :=
32
+ match ex with
33
+ | Exception.internal id k =>
34
+ if id == autoBoundImplicitExceptionId then
35
+ some <| k.getName `localId `x
36
+ else
37
+ none
38
+ | _ => none
39
+
40
+ def throwAlreadyDeclaredUniverseLevel [Monad m] [MonadError m] (u : Name) : m Ξ± :=
41
+ throwError "a universe level named '{u}' has already been declared"
42
+
43
+ -- Throw exception to abort elaboration of the current command without producing any error message
44
+ def throwAbortCommand {Ξ± m} [MonadExcept Exception m] : m Ξ± :=
45
+ throw <| Exception.internal abortCommandExceptionId
46
+
47
+ -- Throw exception to abort elaboration of the current term without producing any error message
48
+ def throwAbortTerm {Ξ± m} [MonadExcept Exception m] : m Ξ± :=
49
+ throw <| Exception.internal abortTermExceptionId
50
+
51
+ -- Throw exception to abort evaluation of the current tactic without producing any error message
52
+ def throwAbortTactic {Ξ± m} [MonadExcept Exception m] : m Ξ± :=
53
+ throw <| Exception.internal abortTacticExceptionId
54
+
55
+ def isAbortTacticException (ex : Exception) : Bool :=
56
+ match ex with
57
+ | Exception.internal id .. => id == abortTacticExceptionId
58
+ | _ => false
59
+
60
+ def isAbortExceptionId (id : InternalExceptionId) : Bool :=
61
+ id == abortCommandExceptionId || id == abortTermExceptionId || id == abortTacticExceptionId
62
+
63
+ def mkMessageCore (fileName : String) (fileMap : FileMap) (data : MessageData) (severity : MessageSeverity) (pos : String.Pos) (endPos : String.Pos) : Message :=
64
+ let pos := fileMap.toPosition pos
65
+ let endPos := fileMap.toPosition endPos
66
+ { fileName, pos, endPos, data, severity }
67
+
68
+ end Lean.Elab
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Extra.lean ADDED
@@ -0,0 +1,588 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Kyle Miller, Sebastian Ullrich
5
+ -/
6
+ prelude
7
+ import Lean.Elab.App
8
+ import Lean.Elab.BuiltinNotation
9
+
10
+ /-! # Auxiliary elaboration functions: AKA custom elaborators -/
11
+
12
+ namespace Lean.Elab.Term
13
+ open Meta
14
+
15
+ private def getMonadForIn (expectedType? : Option Expr) : TermElabM Expr := do
16
+ match expectedType? with
17
+ | none => throwError "invalid 'for_in%' notation, expected type is not available"
18
+ | some expectedType =>
19
+ match (← isTypeApp? expectedType) with
20
+ | some (m, _) => return m
21
+ | none => throwError "invalid 'for_in%' notation, expected type is not of the form `M Ξ±`{indentExpr expectedType}"
22
+
23
+ private def throwForInFailure (forInInstance : Expr) : TermElabM Expr :=
24
+ throwError "failed to synthesize instance for 'for_in%' notation{indentExpr forInInstance}"
25
+
26
+ @[builtin_term_elab forInMacro] def elabForIn : TermElab := fun stx expectedType? => do
27
+ match stx with
28
+ | `(for_in% $col $init $body) =>
29
+ tryPostponeIfNoneOrMVar expectedType?
30
+ let colE ← elabTerm col none
31
+ let m ← getMonadForIn expectedType?
32
+ let colType ← inferType colE
33
+ let elemType ← mkFreshExprMVar (mkSort (mkLevelSucc (← mkFreshLevelMVar)))
34
+ let forInInstance ← try
35
+ mkAppM ``ForIn #[m, colType, elemType]
36
+ catch _ =>
37
+ tryPostpone; throwError "failed to construct 'ForIn' instance for collection{indentExpr colType}\nand monad{indentExpr m}"
38
+ match (← trySynthInstance forInInstance) with
39
+ | .some inst =>
40
+ let forInFn ← mkConst ``forIn
41
+ elabAppArgs forInFn
42
+ (namedArgs := #[{ name := `m, val := Arg.expr m}, { name := `Ξ±, val := Arg.expr elemType }, { name := `self, val := Arg.expr inst }])
43
+ (args := #[Arg.expr colE, Arg.stx init, Arg.stx body])
44
+ (expectedType? := expectedType?)
45
+ (explicit := false) (ellipsis := false) (resultIsOutParamSupport := false)
46
+ | .undef => tryPostpone; throwForInFailure forInInstance
47
+ | .none => throwForInFailure forInInstance
48
+ | _ => throwUnsupportedSyntax
49
+
50
+ @[builtin_term_elab forInMacro'] def elabForIn' : TermElab := fun stx expectedType? => do
51
+ match stx with
52
+ | `(for_in'% $col $init $body) =>
53
+ tryPostponeIfNoneOrMVar expectedType?
54
+ let colE ← elabTerm col none
55
+ let m ← getMonadForIn expectedType?
56
+ let colType ← inferType colE
57
+ let elemType ← mkFreshExprMVar (mkSort (mkLevelSucc (← mkFreshLevelMVar)))
58
+ let forInInstance ←
59
+ try
60
+ let memType ← mkFreshExprMVar (← mkAppM ``Membership #[elemType, colType])
61
+ mkAppM ``ForIn' #[m, colType, elemType, memType]
62
+ catch _ =>
63
+ tryPostpone; throwError "failed to construct `ForIn'` instance for collection{indentExpr colType}\nand monad{indentExpr m}"
64
+ match (← trySynthInstance forInInstance) with
65
+ | .some inst =>
66
+ let forInFn ← mkConst ``forIn'
67
+ elabAppArgs forInFn
68
+ (namedArgs := #[{ name := `m, val := Arg.expr m}, { name := `Ξ±, val := Arg.expr elemType}, { name := `self, val := Arg.expr inst }])
69
+ (args := #[Arg.expr colE, Arg.stx init, Arg.stx body])
70
+ (expectedType? := expectedType?)
71
+ (explicit := false) (ellipsis := false) (resultIsOutParamSupport := false)
72
+ | .undef => tryPostpone; throwForInFailure forInInstance
73
+ | .none => throwForInFailure forInInstance
74
+ | _ => throwUnsupportedSyntax
75
+
76
+ namespace Op
77
+ /-!
78
+
79
+ The elaborator for expression trees of `binop%`, `binop_lazy%`, `leftact%`, `rightact%`, and `unop%` terms.
80
+
81
+ At a high level, the elaborator tries to solve for a type that each of the operands in the expression tree
82
+ can be coerced to, while taking into account the expected type for the entire expression tree.
83
+ Once this type is computed (and if it exists), it inserts coercions where needed.
84
+
85
+ Here are brief descriptions of each of the operator types:
86
+ - `binop% f a b` elaborates `f a b` as a binary operator with two operands `a` and `b`,
87
+ and each operand participates in the protocol.
88
+ - `binop_lazy% f a b` is like `binop%` but elaborates as `f a (fun () => b)`.
89
+ - `unop% f a` elaborates `f a` as a unary operator with one operand `a`, which participates in the protocol.
90
+ - `leftact% f a b` elaborates `f a b` as a left action (the `a` operand "acts upon" the `b` operand).
91
+ Only `b` participates in the protocol since `a` can have an unrelated type, for example scalar multiplication of vectors.
92
+ - `rightact% f a b` elaborates `f a b` as a right action (the `b` operand "acts upon" the `a` operand).
93
+ Only `a` participates in the protocol since `b` can have an unrelated type.
94
+ This is used by `HPow` since, for example, there are both `Real -> Nat -> Real` and `Real -> Real -> Real`
95
+ exponentiation functions, and we prefer the former in the case of `x ^ 2`, but `binop%` would choose the latter. (#2854)
96
+ - There are also `binrel%` and `binrel_no_prop%` (see the docstring for `elabBinRelCore`).
97
+
98
+ The elaborator works as follows:
99
+
100
+ 1- Expand macros.
101
+ 2- Convert `Syntax` object corresponding to the `binop%/...` term into a `Tree`.
102
+ The `toTree` method visits nested `binop%/...` terms and parentheses.
103
+ 3- Synthesize pending metavariables without applying default instances and using the
104
+ `(mayPostpone := true)`.
105
+ 4- Tries to compute a maximal type for the tree computed at step 2.
106
+ We say a type Ξ± is smaller than type Ξ² if there is a (nondependent) coercion from Ξ± to Ξ².
107
+ We are currently ignoring the case we may have cycles in the coercion graph.
108
+ If there are "uncomparable" types Ξ± and Ξ² in the tree, we skip the next step.
109
+ We say two types are "uncomparable" if there isn't a coercion between them.
110
+ Note that two types may be "uncomparable" because some typing information may still be missing.
111
+ 5- We traverse the tree and inject coercions to the "maximal" type when needed.
112
+
113
+ Recall that the coercions are expanded eagerly by the elaborator.
114
+
115
+ Properties:
116
+
117
+ a) Given `n : Nat` and `i : Nat`, it can successfully elaborate `n + i` and `i + n`. Recall that Lean 3
118
+ fails on the former.
119
+
120
+ b) The coercions are inserted in the "leaves" like in Lean 3.
121
+
122
+ c) There are no coercions "hidden" inside instances, and we can elaborate
123
+ ```
124
+ axiom Int.add_comm (i j : Int) : i + j = j + i
125
+
126
+ example (n : Nat) (i : Int) : n + i = i + n := by
127
+ rw [Int.add_comm]
128
+ ```
129
+ Recall that the `rw` tactic used to fail because our old `binop%` elaborator would hide
130
+ coercions inside of a `HAdd` instance.
131
+
132
+ Remarks:
133
+
134
+ * In the new `binop%` and related elaborators the decision whether a coercion will be inserted or not
135
+ is made at `binop%` elaboration time. This was not the case in the old elaborator.
136
+ For example, an instance, such as `HAdd Int ?m ?n`, could be created when executing
137
+ the `binop%` elaborator, and only resolved much later. We try to minimize this problem
138
+ by synthesizing pending metavariables at step 3.
139
+
140
+ * For types containing heterogeneous operators (e.g., matrix multiplication), step 4 will fail
141
+ and we will skip coercion insertion. For example, `x : Matrix Real 5 4` and `y : Matrix Real 4 8`,
142
+ there is no coercion `Matrix Real 5 4` from `Matrix Real 4 8` and vice-versa, but
143
+ `x * y` is elaborated successfully and has type `Matrix Real 5 8`.
144
+
145
+ * The `leftact%` and `rightact%` elaborators are to handle binary operations where only one of
146
+ the arguments participates in the protocol. For example, in `2 ^ n + y` with `n : Nat` and `y : Real`,
147
+ we do not want to coerce `n` to be a real as well, but we do want to elaborate `2 : Real`.
148
+ -/
149
+
150
+ private inductive BinOpKind where
151
+ | regular -- `binop%`
152
+ | lazy -- `binop_lazy%`
153
+ | leftact -- `leftact%`
154
+ | rightact -- `rightact%`
155
+ deriving BEq
156
+
157
+ private inductive Tree where
158
+ /--
159
+ Leaf of the tree.
160
+ We store the `infoTrees` generated when elaborating `val`. These trees become
161
+ subtrees of the infotree nodes generated for `op` nodes.
162
+ -/
163
+ | term (ref : Syntax) (infoTrees : PersistentArray InfoTree) (val : Expr)
164
+ /--
165
+ `ref` is the original syntax that expanded into `binop%/...`.
166
+ -/
167
+ | binop (ref : Syntax) (kind : BinOpKind) (f : Expr) (lhs rhs : Tree)
168
+ /--
169
+ `ref` is the original syntax that expanded into `unop%`.
170
+ -/
171
+ | unop (ref : Syntax) (f : Expr) (arg : Tree)
172
+ /--
173
+ Used for assembling the info tree. We store this information
174
+ to make sure "go to definition" behaves similarly to notation defined without using `binop%` helper elaborator.
175
+ -/
176
+ | macroExpansion (macroName : Name) (stx stx' : Syntax) (nested : Tree)
177
+
178
+
179
+ private partial def toTree (s : Syntax) : TermElabM Tree := do
180
+ /-
181
+ Remark: ew used to use `expandMacros` here, but this is a bad idiom
182
+ because we do not record the macro expansion information in the info tree.
183
+ We now manually expand the notation in the `go` function, and save
184
+ the macro declaration names in the `op` nodes.
185
+ -/
186
+ let result ← go s
187
+ synthesizeSyntheticMVars (postpone := .yes)
188
+ return result
189
+ where
190
+ go (s : Syntax) := do
191
+ match s with
192
+ | `(binop% $f $lhs $rhs) => processBinOp s .regular f lhs rhs
193
+ | `(binop_lazy% $f $lhs $rhs) => processBinOp s .lazy f lhs rhs
194
+ | `(unop% $f $arg) => processUnOp s f arg
195
+ | `(leftact% $f $lhs $rhs) => processBinOp s .leftact f lhs rhs
196
+ | `(rightact% $f $lhs $rhs) => processBinOp s .rightact f lhs rhs
197
+ | `(($e)) =>
198
+ if hasCDot e then
199
+ processLeaf s
200
+ else
201
+ go e
202
+ | _ =>
203
+ withRef s do
204
+ match (← liftMacroM <| expandMacroImpl? (← getEnv) s) with
205
+ | some (macroName, s?) =>
206
+ let s' ← liftMacroM <| liftExcept s?
207
+ withPushMacroExpansionStack s s' do
208
+ return .macroExpansion macroName s s' (← go s')
209
+ | none => processLeaf s
210
+
211
+ processBinOp (ref : Syntax) (kind : BinOpKind) (f lhs rhs : Syntax) := do
212
+ let some f οΏ½οΏ½ resolveId? f | throwUnknownConstantAt f f.getId
213
+ -- treat corresponding argument as leaf for `leftact/rightact`
214
+ let lhs ← if kind == .leftact then processLeaf lhs else go lhs
215
+ let rhs ← if kind == .rightact then processLeaf rhs else go rhs
216
+ return .binop ref kind f lhs rhs
217
+
218
+ processUnOp (ref : Syntax) (f arg : Syntax) := do
219
+ let some f ← resolveId? f | throwUnknownConstantAt f f.getId
220
+ return .unop ref f (← go arg)
221
+
222
+ processLeaf (s : Syntax) := do
223
+ let e ← elabTerm s none
224
+ let info ← getResetInfoTrees
225
+ return .term s info e
226
+
227
+ -- Auxiliary function used at `analyze`
228
+ private def hasCoe (fromType toType : Expr) : TermElabM Bool := do
229
+ if (← getEnv).contains ``CoeT then
230
+ withLocalDeclD `x fromType fun x => do
231
+ match ← coerceSimple? x toType with
232
+ | .some _ => return true
233
+ | .none => return false
234
+ | .undef => return false -- TODO: should we do something smarter here?
235
+ else
236
+ return false
237
+
238
+ private structure AnalyzeResult where
239
+ max? : Option Expr := none
240
+ /-- `true` if there are two types `Ξ±` and `Ξ²` where we don't have coercions in any direction. -/
241
+ hasUncomparable : Bool := false
242
+ /-- `true` if there are any leaf terms with an unknown type (according to `isUnknown`). -/
243
+ hasUnknown : Bool := false
244
+
245
+ private def isUnknown : Expr β†’ Bool
246
+ | .mvar .. => true
247
+ | .app f _ => isUnknown f
248
+ | .letE _ _ _ b _ => isUnknown b
249
+ | .mdata _ b => isUnknown b
250
+ | _ => false
251
+
252
+ private def analyze (t : Tree) (expectedType? : Option Expr) : TermElabM AnalyzeResult := do
253
+ let max? ←
254
+ match expectedType? with
255
+ | none => pure none
256
+ | some expectedType =>
257
+ let expectedType := (← instantiateMVars expectedType).cleanupAnnotations
258
+ if isUnknown expectedType then pure none else pure (some expectedType)
259
+ (go t *> get).run' { max? }
260
+ where
261
+ go (t : Tree) : StateRefT AnalyzeResult TermElabM Unit := do
262
+ unless (← get).hasUncomparable do
263
+ match t with
264
+ | .macroExpansion _ _ _ nested => go nested
265
+ | .binop _ .leftact _ _ rhs => go rhs
266
+ | .binop _ .rightact _ lhs _ => go lhs
267
+ | .binop _ _ _ lhs rhs => go lhs; go rhs
268
+ | .unop _ _ arg => go arg
269
+ | .term _ _ val =>
270
+ let type := (← instantiateMVars (← inferType val)).cleanupAnnotations
271
+ if isUnknown type then
272
+ modify fun s => { s with hasUnknown := true }
273
+ else
274
+ match (← get).max? with
275
+ | none => modify fun s => { s with max? := type }
276
+ | some max =>
277
+ /-
278
+ Remark: Previously, we used `withNewMCtxDepth` to prevent metavariables in `max` and `type` from being assigned.
279
+
280
+ Reason: This is a heuristic procedure for introducing coercions in scenarios such as:
281
+ - Given `(n : Nat) (i : Int)`, elaborate `n = i`. The coercion must be inserted at `n`.
282
+ Consider the elaboration problem `(n + 0) + i`, where the type of term `0` is a metavariable.
283
+ We do not want it to be elaborated as `(Int.ofNat n + Int.ofNat (0 : Nat)) + i`; instead, we prefer the result to be `(Int.ofNat n + (0 : Int)) + i`.
284
+ Here is another example where we avoid assigning metavariables: `max := BitVec n` and `type := BitVec ?m`.
285
+
286
+ However, the combination `withNewMCtxDepth <| isDefEqGuarded max type` introduced performance issues in several
287
+ Mathlib files because `isDefEq` was spending a lot of time unfolding definitions in `max` and `type` before failing.
288
+
289
+ To address this issue, we allowed only reducible definitions to be unfolded during this check, using
290
+ `withNewMCtxDepth <| withReducible <| isDefEqGuarded max type`. This change fixed some performance issues but created new ones.
291
+ Lean was now spending time trying to use `hasCoe`, likely occurring in places where `withNewMCtxDepth <| isDefEqGuarded max type`
292
+ used to succeed but was now failing after we introduced `withReducible`.
293
+
294
+ We then considered using just `isDefEqGuarded max type` and changing the definition of `isUnknown`. In the new definition,
295
+ the else-case would be `| e => e.hasExprMVar` instead of `| _ => false`. However, we could not even compile this repo using
296
+ this configuration. The problem arises because some files require coercions even when `max` contains metavariables,
297
+ for example: `max := Option ?m` and `type := Name`.
298
+
299
+ As a result, rather than restricting reducibility, we decided to set `Meta.Config.isDefEqStuckEx := true`.
300
+ This means that if `isDefEq` encounters a subproblem `?m =?= a` where `?m` is non-assignable, it aborts the test
301
+ instead of unfolding definitions.
302
+ -/
303
+ unless (← withNewMCtxDepth <| withConfig (fun config => { config with isDefEqStuckEx := true }) <| isDefEqGuarded max type) do
304
+ if (← hasCoe type max) then
305
+ return ()
306
+ else if (← hasCoe max type) then
307
+ modify fun s => { s with max? := type }
308
+ else
309
+ trace[Elab.binop] "uncomparable types: {max}, {type}"
310
+ modify fun s => { s with hasUncomparable := true }
311
+
312
+ private def mkBinOp (lazy : Bool) (f : Expr) (lhs rhs : Expr) : TermElabM Expr := do
313
+ let mut rhs := rhs
314
+ if lazy then
315
+ rhs ← mkFunUnit rhs
316
+ elabAppArgs f #[] #[Arg.expr lhs, Arg.expr rhs] (expectedType? := none) (explicit := false) (ellipsis := false) (resultIsOutParamSupport := false)
317
+
318
+ private def mkUnOp (f : Expr) (arg : Expr) : TermElabM Expr := do
319
+ elabAppArgs f #[] #[Arg.expr arg] (expectedType? := none) (explicit := false) (ellipsis := false) (resultIsOutParamSupport := false)
320
+
321
+ private def toExprCore (t : Tree) : TermElabM Expr := do
322
+ match t with
323
+ | .term _ trees e =>
324
+ modifyInfoState (fun s => { s with trees := s.trees ++ trees }); return e
325
+ | .binop ref kind f lhs rhs =>
326
+ withRef ref <|
327
+ withTermInfoContext' .anonymous ref do
328
+ mkBinOp (kind == .lazy) f (← toExprCore lhs) (← toExprCore rhs)
329
+ | .unop ref f arg =>
330
+ withRef ref <|
331
+ withTermInfoContext' .anonymous ref do
332
+ mkUnOp f (← toExprCore arg)
333
+ | .macroExpansion macroName stx stx' nested =>
334
+ withRef stx <|
335
+ withTermInfoContext' macroName stx <|
336
+ withMacroExpansion stx stx' <|
337
+ toExprCore nested
338
+
339
+ /--
340
+ Auxiliary function to decide whether we should coerce `f`'s argument to `maxType` or not.
341
+ - `f` is a binary operator.
342
+ - `lhs == true` (`lhs == false`) if are trying to coerce the left-argument (right-argument).
343
+ This function assumes `f` is a heterogeneous operator (e.g., `HAdd.hAdd`, `HMul.hMul`, etc).
344
+ It returns true IF
345
+ - `f` is a constant of the form `Cls.op` where `Cls` is a class name, and
346
+ - `maxType` is of the form `C ...` where `C` is a constant, and
347
+ - There are more than one default instance. That is, it assumes the class `Cls` for the heterogeneous operator `f`, and
348
+ always has the monomorphic instance. (e.g., for `HAdd`, we have `instance [Add Ξ±] : HAdd Ξ± Ξ± Ξ±`), and
349
+ - If `lhs == true`, then there is a default instance of the form `Cls _ (C ..) _`, and
350
+ - If `lhs == false`, then there is a default instance of the form `Cls (C ..) _ _`.
351
+
352
+ The motivation is to support default instances such as
353
+ ```
354
+ @[default_instance high]
355
+ instance [Mul Ξ±] : HMul Ξ± (Array Ξ±) (Array Ξ±) where
356
+ hMul a as := as.map (a * Β·)
357
+
358
+ #eval 2 * #[3, 4, 5]
359
+ ```
360
+ If the type of an argument is unknown we should not coerce it to `maxType` because it would prevent
361
+ the default instance above from being even tried.
362
+ -/
363
+ private def hasHeterogeneousDefaultInstances (f : Expr) (maxType : Expr) (lhs : Bool) : MetaM Bool := do
364
+ let .const fName .. := f | return false
365
+ let .const typeName .. := maxType.getAppFn | return false
366
+ let className := fName.getPrefix
367
+ let defInstances ← getDefaultInstances className
368
+ if defInstances.length ≀ 1 then return false
369
+ for (instName, _) in defInstances do
370
+ if let .app (.app (.app _heteroClass lhsType) rhsType) _resultType :=
371
+ (← getConstInfo instName).type.getForallBody then
372
+ if lhs && rhsType.isAppOf typeName then return true
373
+ if !lhs && lhsType.isAppOf typeName then return true
374
+ return false
375
+
376
+ /--
377
+ Return `true` if polymorphic function `f` has a homogeneous instance of `maxType`.
378
+ The coercions to `maxType` only makes sense if such instance exists.
379
+
380
+ For example, suppose `maxType` is `Int`, and `f` is `HPow.hPow`. Then,
381
+ adding coercions to `maxType` only make sense if we have an instance `HPow Int Int Int`.
382
+ -/
383
+ private def hasHomogeneousInstance (f : Expr) (maxType : Expr) : MetaM Bool := do
384
+ let .const fName .. := f | return false
385
+ let className := fName.getPrefix
386
+ try
387
+ let inst ← mkAppM className #[maxType, maxType, maxType]
388
+ return (← trySynthInstance inst) matches .some _
389
+ catch _ =>
390
+ return false
391
+
392
+ mutual
393
+ /--
394
+ Try to coerce elements in the `t` to `maxType` when needed.
395
+ If the type of an element in `t` is unknown we only coerce it to `maxType` if `maxType` does not have heterogeneous
396
+ default instances. This extra check is approximated by `hasHeterogeneousDefaultInstances`.
397
+
398
+ Remark: If `maxType` does not implement heterogeneous default instances, we do want to assign unknown types `?m` to
399
+ `maxType` because it produces better type information propagation. Our test suite has many tests that would break if
400
+ we don't do this. For example, consider the term
401
+ ```
402
+ eq_of_isEqvAux a b hsz (i+1) (Nat.succ_le_of_lt h) heqv.2
403
+ ```
404
+ `Nat.succ_le_of_lt h` type depends on `i+1`, but `i+1` only reduces to `Nat.succ i` if we know that `1` is a `Nat`.
405
+ There are several other examples like that in our test suite, and one can find them by just replacing the
406
+ `← hasHeterogeneousDefaultInstances f maxType lhs` test with `true`
407
+
408
+
409
+ Remark: if `hasHeterogeneousDefaultInstances` implementation is not good enough we should refine it in the future.
410
+ -/
411
+ private partial def applyCoe (t : Tree) (maxType : Expr) (isPred : Bool) : TermElabM Tree := do
412
+ go t none false isPred
413
+ where
414
+ go (t : Tree) (f? : Option Expr) (lhs : Bool) (isPred : Bool) : TermElabM Tree := do
415
+ match t with
416
+ | .binop ref .leftact f lhs rhs =>
417
+ return .binop ref .leftact f lhs (← go rhs none false false)
418
+ | .binop ref .rightact f lhs rhs =>
419
+ return .binop ref .rightact f (← go lhs none false false) rhs
420
+ | .binop ref kind f lhs rhs =>
421
+ /-
422
+ We only keep applying coercions to `maxType` if `f` is predicate or
423
+ `f` has a homogeneous instance with `maxType`. See `hasHomogeneousInstance` for additional details.
424
+
425
+ Remark: We assume `binrel%` elaborator is only used with homogeneous predicates.
426
+ -/
427
+ if (← pure isPred <||> hasHomogeneousInstance f maxType) then
428
+ return .binop ref kind f (← go lhs f true false) (← go rhs f false false)
429
+ else
430
+ let r ← withRef ref do
431
+ mkBinOp (kind == .lazy) f (← toExpr lhs none) (← toExpr rhs none)
432
+ let infoTrees ← getResetInfoTrees
433
+ return .term ref infoTrees r
434
+ | .unop ref f arg =>
435
+ return .unop ref f (← go arg none false false)
436
+ | .term ref trees e =>
437
+ let type := (← instantiateMVars (← inferType e)).cleanupAnnotations
438
+ trace[Elab.binop] "visiting {e} : {type} =?= {maxType}"
439
+ if isUnknown type then
440
+ if let some f := f? then
441
+ if (← hasHeterogeneousDefaultInstances f maxType lhs) then
442
+ -- See comment at `hasHeterogeneousDefaultInstances`
443
+ return t
444
+ if (← isDefEqGuarded maxType type) then
445
+ return t
446
+ else
447
+ trace[Elab.binop] "added coercion: {e} : {type} => {maxType}"
448
+ withRef ref <| return .term ref trees (← mkCoe maxType e)
449
+ | .macroExpansion macroName stx stx' nested =>
450
+ withRef stx <| withPushMacroExpansionStack stx stx' do
451
+ return .macroExpansion macroName stx stx' (← go nested f? lhs isPred)
452
+
453
+ private partial def toExpr (tree : Tree) (expectedType? : Option Expr) : TermElabM Expr := do
454
+ let r ← analyze tree expectedType?
455
+ trace[Elab.binop] "hasUncomparable: {r.hasUncomparable}, hasUnknown: {r.hasUnknown}, maxType: {r.max?}"
456
+ if r.hasUncomparable || r.max?.isNone then
457
+ let result ← toExprCore tree
458
+ ensureHasType expectedType? result
459
+ else
460
+ let result ← toExprCore (← applyCoe tree r.max?.get! (isPred := false))
461
+ unless r.hasUnknown do
462
+ -- Record the resulting maxType calculation.
463
+ -- We can do this when all the types are known, since in this case `hasUncomparable` is valid.
464
+ -- If they're not known, recording maxType like this can lead to heterogeneous operations failing to elaborate.
465
+ discard <| isDefEqGuarded (← inferType result) r.max?.get!
466
+ trace[Elab.binop] "result: {result}"
467
+ ensureHasType expectedType? result
468
+
469
+ end
470
+
471
+ def elabOp : TermElab := fun stx expectedType? => do
472
+ toExpr (← toTree stx) expectedType?
473
+
474
+ @[builtin_term_elab binop] def elabBinOp : TermElab := elabOp
475
+ @[builtin_term_elab binop_lazy] def elabBinOpLazy : TermElab := elabOp
476
+ @[builtin_term_elab leftact] def elabLeftact : TermElab := elabOp
477
+ @[builtin_term_elab rightact] def elabRightact : TermElab := elabOp
478
+ @[builtin_term_elab unop] def elabUnOp : TermElab := elabOp
479
+
480
+ /--
481
+ Elaboration functions for `binrel%` and `binrel_no_prop%` notations.
482
+ We use the infrastructure for `binop%` to make sure we propagate information between the left and right hand sides
483
+ of a binary relation.
484
+
485
+ - `binrel% R x y` elaborates `R x y` using the `binop%/...` expression trees in both `x` and `y`.
486
+ It is similar to how `binop% R x y` elaborates but with a significant difference:
487
+ it does not use the expected type when computing the types of the operands.
488
+ - `binrel_no_prop% R x y` elaborates `R x y` like `binrel% R x y`, but if the resulting type for `x` and `y`
489
+ is `Prop` they are coerced to `Bool`.
490
+ This is used for relations such as `==` which do not support `Prop`, but we still want
491
+ to be able to write `(5 > 2) == (2 > 1)` for example.
492
+ -/
493
+ def elabBinRelCore (noProp : Bool) (stx : Syntax) (expectedType? : Option Expr) : TermElabM Expr := do
494
+ match (← resolveId? stx[1]) with
495
+ | some f => withSynthesizeLight do
496
+ /-
497
+ We used to use `withSynthesize (mayPostpone := true)` here instead of `withSynthesizeLight` here.
498
+ It seems too much to apply default instances at binary relations. For example, we cannot elaborate
499
+ ```
500
+ def as : List Int := [-1, 2, 0, -3, 4]
501
+ #eval as.map fun a => ite (a β‰₯ 0) [a] []
502
+ ```
503
+ The problem is that when elaborating `a β‰₯ 0` we don't know yet that `a` is an `Int`.
504
+ Then, by applying default instances, we apply the default instance to `0` that forces it to become an `Int`,
505
+ and Lean infers that `a` has type `Nat`.
506
+ Then, later we get a type error because `as` is `List Int` instead of `List Nat`.
507
+ This behavior is quite counterintuitive since if we avoid this elaborator by writing
508
+ ```
509
+ def as : List Int := [-1, 2, 0, -3, 4]
510
+ #eval as.map fun a => ite (GE.ge a 0) [a] []
511
+ ```
512
+ everything works.
513
+ However, there is a drawback of using `withSynthesizeLight` instead of `withSynthesize (mayPostpone := true)`.
514
+ The following cannot be elaborated
515
+ ```
516
+ have : (0 == 1) = false := rfl
517
+ ```
518
+ We get a type error at `rfl`. `0 == 1` only reduces to `false` after we have applied the default instances that force
519
+ the numeral to be `Nat`. We claim this is defensible behavior because the same happens if we do not use this elaborator.
520
+ ```
521
+ have : (BEq.beq 0 1) = false := rfl
522
+ ```
523
+ We can improve this failure in the future by applying default instances before reporting a type mismatch.
524
+ -/
525
+ let lhsStx := stx[2]
526
+ let rhsStx := stx[3]
527
+ let lhs ← withRef lhsStx <| toTree lhsStx
528
+ let rhs ← withRef rhsStx <| toTree rhsStx
529
+ let tree := .binop stx .regular f lhs rhs
530
+ let r ← analyze tree none
531
+ trace[Elab.binrel] "hasUncomparable: {r.hasUncomparable}, hasUnknown: {r.hasUnknown}, maxType: {r.max?}"
532
+ if r.hasUncomparable || r.max?.isNone then
533
+ -- Use default elaboration strategy + `toBoolIfNecessary`
534
+ let lhs ← toExprCore lhs
535
+ let rhs ← toExprCore rhs
536
+ let lhs ← withRef lhsStx <| toBoolIfNecessary lhs
537
+ let rhs ← withRef rhsStx <| toBoolIfNecessary rhs
538
+ let lhsType ← inferType lhs
539
+ let rhs ← withRef rhsStx <| ensureHasType lhsType rhs
540
+ elabAppArgs f #[] #[Arg.expr lhs, Arg.expr rhs] expectedType? (explicit := false) (ellipsis := false) (resultIsOutParamSupport := false)
541
+ else
542
+ let mut maxType := r.max?.get!
543
+ /- If `noProp == true` and `maxType` is `Prop`, then set `maxType := Bool`. `See toBoolIfNecessary` -/
544
+ if noProp then
545
+ if (← withNewMCtxDepth <| isDefEq maxType (mkSort levelZero)) then
546
+ maxType := Lean.mkConst ``Bool
547
+ let result ← toExprCore (← applyCoe tree maxType (isPred := true))
548
+ trace[Elab.binrel] "result: {result}"
549
+ return result
550
+ | none => throwUnknownConstantAt stx[1] stx[1].getId
551
+ where
552
+ /-- If `noProp == true` and `e` has type `Prop`, then coerce it to `Bool`. -/
553
+ toBoolIfNecessary (e : Expr) : TermElabM Expr := do
554
+ if noProp then
555
+ -- We use `withNewMCtxDepth` to make sure metavariables are not assigned
556
+ if (← withNewMCtxDepth <| isDefEq (← inferType e) (mkSort levelZero)) then
557
+ return (← ensureHasType (Lean.mkConst ``Bool) e)
558
+ return e
559
+
560
+ @[builtin_term_elab binrel] def elabBinRel : TermElab := elabBinRelCore false
561
+
562
+ @[builtin_term_elab binrel_no_prop] def elabBinRelNoProp : TermElab := elabBinRelCore true
563
+
564
+ @[builtin_term_elab defaultOrOfNonempty]
565
+ def elabDefaultOrNonempty : TermElab := fun stx expectedType? => do
566
+ tryPostponeIfNoneOrMVar expectedType?
567
+ match expectedType? with
568
+ | none => throwError "invalid 'default_or_ofNonempty%', expected type is not known"
569
+ | some expectedType =>
570
+ try
571
+ mkDefault expectedType
572
+ catch ex => try
573
+ mkOfNonempty expectedType
574
+ catch _ =>
575
+ if stx[1].isNone then
576
+ throw ex
577
+ else
578
+ -- It is in the context of an `unsafe` constant. We can use sorry instead.
579
+ -- Another option is to make a recursive application since it is unsafe.
580
+ mkLabeledSorry expectedType false (unique := true)
581
+
582
+ builtin_initialize
583
+ registerTraceClass `Elab.binop
584
+ registerTraceClass `Elab.binrel
585
+
586
+ end Op
587
+
588
+ end Lean.Elab.Term
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Frontend.lean ADDED
@@ -0,0 +1,218 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2019 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Sebastian Ullrich
5
+ -/
6
+ prelude
7
+ import Lean.Language.Lean
8
+ import Lean.Util.Profile
9
+ import Lean.Server.References
10
+ import Lean.Util.Profiler
11
+
12
+ namespace Lean.Elab.Frontend
13
+
14
+ structure State where
15
+ commandState : Command.State
16
+ parserState : Parser.ModuleParserState
17
+ cmdPos : String.Pos
18
+ commands : Array Syntax := #[]
19
+ deriving Nonempty
20
+
21
+ structure Context where
22
+ inputCtx : Parser.InputContext
23
+
24
+ abbrev FrontendM := ReaderT Context $ StateRefT State IO
25
+
26
+ def setCommandState (commandState : Command.State) : FrontendM Unit :=
27
+ modify fun s => { s with commandState := commandState }
28
+
29
+ @[inline] def runCommandElabM (x : Command.CommandElabM Ξ±) : FrontendM Ξ± := do
30
+ let ctx ← read
31
+ let s ← get
32
+ let cmdCtx : Command.Context := {
33
+ cmdPos := s.cmdPos
34
+ fileName := ctx.inputCtx.fileName
35
+ fileMap := ctx.inputCtx.fileMap
36
+ snap? := none
37
+ cancelTk? := none
38
+ }
39
+ match (← liftM <| EIO.toIO' <| (x cmdCtx).run s.commandState) with
40
+ | Except.error e => throw <| IO.Error.userError s!"unexpected internal error: {← e.toMessageData.toString}"
41
+ | Except.ok (a, sNew) => setCommandState sNew; return a
42
+
43
+ def elabCommandAtFrontend (stx : Syntax) : FrontendM Unit := do
44
+ runCommandElabM do
45
+ let initMsgs ← modifyGet fun st => (st.messages, { st with messages := {} })
46
+ Command.elabCommandTopLevel stx
47
+ let mut msgs := (← get).messages
48
+ modify ({ Β· with messages := initMsgs ++ msgs })
49
+
50
+ def updateCmdPos : FrontendM Unit := do
51
+ modify fun s => { s with cmdPos := s.parserState.pos }
52
+
53
+ def getParserState : FrontendM Parser.ModuleParserState := do pure (← get).parserState
54
+ def getCommandState : FrontendM Command.State := do pure (← get).commandState
55
+ def setParserState (ps : Parser.ModuleParserState) : FrontendM Unit := modify fun s => { s with parserState := ps }
56
+ def setMessages (msgs : MessageLog) : FrontendM Unit := modify fun s => { s with commandState := { s.commandState with messages := msgs } }
57
+ def getInputContext : FrontendM Parser.InputContext := do pure (← read).inputCtx
58
+
59
+ def processCommand : FrontendM Bool := do
60
+ updateCmdPos
61
+ let cmdState ← getCommandState
62
+ let ictx ← getInputContext
63
+ let pstate ← getParserState
64
+ let scope := cmdState.scopes.head!
65
+ let pmctx := { env := cmdState.env, options := scope.opts, currNamespace := scope.currNamespace, openDecls := scope.openDecls }
66
+ match profileit "parsing" scope.opts fun _ => Parser.parseCommand ictx pmctx pstate cmdState.messages with
67
+ | (cmd, ps, messages) =>
68
+ modify fun s => { s with commands := s.commands.push cmd }
69
+ setParserState ps
70
+ setMessages messages
71
+ elabCommandAtFrontend cmd
72
+ pure (Parser.isTerminalCommand cmd)
73
+
74
+ partial def processCommands : FrontendM Unit := do
75
+ let done ← processCommand
76
+ unless done do
77
+ processCommands
78
+
79
+ end Frontend
80
+
81
+ open Frontend
82
+
83
+ structure IncrementalState extends State where
84
+ inputCtx : Parser.InputContext
85
+ initialSnap : Language.Lean.CommandParsedSnapshot
86
+ deriving Nonempty
87
+
88
+ open Language in
89
+ /--
90
+ Variant of `IO.processCommands` that allows for potential incremental reuse. Pass in the result of a
91
+ previous invocation done with the same state (but usually different input context) to allow for
92
+ reuse.
93
+ -/
94
+ partial def IO.processCommandsIncrementally (inputCtx : Parser.InputContext)
95
+ (parserState : Parser.ModuleParserState) (commandState : Command.State)
96
+ (old? : Option IncrementalState) :
97
+ BaseIO IncrementalState := do
98
+ let task ← Language.Lean.processCommands inputCtx parserState commandState
99
+ (old?.map fun old => (old.inputCtx, old.initialSnap))
100
+ go task.get task #[]
101
+ where
102
+ go initialSnap t commands :=
103
+ let snap := t.get
104
+ let commands := commands.push snap
105
+ if let some next := snap.nextCmdSnap? then
106
+ go initialSnap next.task commands
107
+ else
108
+ -- Opting into reuse also enables incremental reporting, so make sure to collect messages from
109
+ -- all snapshots
110
+ let messages := toSnapshotTree initialSnap
111
+ |>.getAll.map (Β·.diagnostics.msgLog)
112
+ |>.foldl (Β· ++ Β·) {}
113
+ -- In contrast to messages, we should collect info trees only from the top-level command
114
+ -- snapshots as they subsume any info trees reported incrementally by their children.
115
+ let trees := commands.map (Β·.elabSnap.infoTreeSnap.get.infoTree?) |>.filterMap id |>.toPArray'
116
+ return {
117
+ commandState := { snap.elabSnap.resultSnap.get.cmdState with messages, infoState.trees := trees }
118
+ parserState := snap.parserState
119
+ cmdPos := snap.parserState.pos
120
+ commands := commands.map (Β·.stx)
121
+ inputCtx, initialSnap
122
+ }
123
+
124
+ def IO.processCommands (inputCtx : Parser.InputContext) (parserState : Parser.ModuleParserState)
125
+ (commandState : Command.State) : IO State := do
126
+ let st ← IO.processCommandsIncrementally inputCtx parserState commandState none
127
+ return st.toState
128
+
129
+ def process (input : String) (env : Environment) (opts : Options) (fileName : Option String := none) : IO (Environment Γ— MessageLog) := do
130
+ let fileName := fileName.getD "<input>"
131
+ let inputCtx := Parser.mkInputContext input fileName
132
+ let s ← IO.processCommands inputCtx { : Parser.ModuleParserState } (Command.mkState env {} opts)
133
+ pure (s.commandState.env, s.commandState.messages)
134
+
135
+ def runFrontend
136
+ (input : String)
137
+ (opts : Options)
138
+ (fileName : String)
139
+ (mainModuleName : Name)
140
+ (trustLevel : UInt32 := 0)
141
+ (oleanFileName? : Option System.FilePath := none)
142
+ (ileanFileName? : Option System.FilePath := none)
143
+ (jsonOutput : Bool := false)
144
+ (errorOnKinds : Array Name := #[])
145
+ (plugins : Array System.FilePath := #[])
146
+ (printStats : Bool := false)
147
+ (setup? : Option ModuleSetup := none)
148
+ : IO (Option Environment) := do
149
+ let startTime := (← IO.monoNanosNow).toFloat / 1000000000
150
+ let inputCtx := Parser.mkInputContext input fileName
151
+ let opts := Lean.internal.cmdlineSnapshots.setIfNotSet opts true
152
+ -- default to async elaboration; see also `Elab.async` docs
153
+ let opts := Elab.async.setIfNotSet opts true
154
+ let ctx := { inputCtx with }
155
+ let setup stx := do
156
+ if let some setup := setup? then
157
+ liftM <| setup.dynlibs.forM Lean.loadDynlib
158
+ return .ok {
159
+ trustLevel
160
+ mainModuleName := setup.name
161
+ isModule := strictOr setup.isModule stx.isModule
162
+ imports := setup.imports?.getD stx.imports
163
+ plugins := plugins ++ setup.plugins
164
+ importArts := setup.importArts
165
+ -- override cmdline options with setup options
166
+ opts := opts.mergeBy (fun _ _ hOpt => hOpt) setup.options.toOptions
167
+ }
168
+ else
169
+ return .ok {
170
+ imports := stx.imports
171
+ isModule := stx.isModule
172
+ mainModuleName, opts, trustLevel, plugins
173
+ }
174
+ let processor := Language.Lean.process
175
+ let snap ← processor setup none ctx
176
+ let snaps := Language.toSnapshotTree snap
177
+ let severityOverrides := errorOnKinds.foldl (Β·.insert Β· .error) {}
178
+
179
+ -- reporting should be done before any early exit from the function
180
+ let hasErrors ← snaps.runAndReport opts jsonOutput severityOverrides
181
+
182
+ let some cmdState := Language.Lean.waitForFinalCmdState? snap
183
+ | return none
184
+ let env := cmdState.env
185
+ let finalOpts := cmdState.scopes[0]!.opts
186
+
187
+ -- stats should be displayed even if there are (non-import) errors
188
+ if printStats then
189
+ env.displayStats
190
+
191
+ if hasErrors then
192
+ return none
193
+
194
+ if let some oleanFileName := oleanFileName? then
195
+ profileitIO ".olean serialization" finalOpts do
196
+ writeModule env oleanFileName
197
+
198
+ if let some ileanFileName := ileanFileName? then
199
+ let trees := snaps.getAll.flatMap (match Β·.infoTree? with | some t => #[t] | _ => #[])
200
+ let references := Lean.Server.findModuleRefs inputCtx.fileMap trees (localVars := false)
201
+ let ilean := {
202
+ module := mainModuleName
203
+ directImports := Server.collectImports ⟨snap.stx⟩
204
+ references := ← references.toLspModuleRefs
205
+ : Lean.Server.Ilean
206
+ }
207
+ IO.FS.writeFile ileanFileName $ Json.compress $ toJson ilean
208
+
209
+ if let some out := trace.profiler.output.get? opts then
210
+ let traceStates := snaps.getAll.map (Β·.traces)
211
+ let profile ← Firefox.Profile.export mainModuleName.toString startTime traceStates opts
212
+ IO.FS.writeFile ⟨out⟩ <| Json.compress <| toJson profile
213
+
214
+ -- no point in freeing the snapshot graph and all referenced data this close to process exit
215
+ Runtime.forget snaps
216
+ return some env
217
+
218
+ end Lean.Elab
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/GenInjective.lean ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2021 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Command
8
+ import Lean.Meta.Injective
9
+
10
+ namespace Lean.Elab.Command
11
+
12
+ @[builtin_command_elab genInjectiveTheorems] def elabGenInjectiveTheorems : CommandElab := fun stx => do
13
+ liftTermElabM do
14
+ let declName ← realizeGlobalConstNoOverloadWithInfo stx[1]
15
+ Meta.mkInjectiveTheorems declName
16
+
17
+ end Lean.Elab.Command
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/GuardMsgs.lean ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2023 Kyle Miller. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Kyle Miller
5
+ -/
6
+ prelude
7
+ import Lean.Elab.Notation
8
+ import Lean.Util.Diff
9
+ import Lean.Server.CodeActions.Attr
10
+
11
+ /-! `#guard_msgs` command for testing commands
12
+
13
+ This module defines a command to test that another command produces the expected messages.
14
+ See the docstring on the `#guard_msgs` command.
15
+ -/
16
+
17
+ open Lean Parser.Tactic Elab Command
18
+
19
+ register_builtin_option guard_msgs.diff : Bool := {
20
+ defValue := true
21
+ descr := "When true, show a diff between expected and actual messages if they don't match. "
22
+ }
23
+
24
+
25
+ namespace Lean.Elab.Tactic.GuardMsgs
26
+
27
+ /-- Gives a string representation of a message without source position information.
28
+ Ensures the message ends with a '\n'. -/
29
+ private def messageToStringWithoutPos (msg : Message) : BaseIO String := do
30
+ let mut str ← msg.data.toString
31
+ unless msg.caption == "" do
32
+ str := msg.caption ++ ":\n" ++ str
33
+ if !("\n".isPrefixOf str) then str := " " ++ str
34
+ if msg.isTrace then
35
+ str := "trace:" ++ str
36
+ else
37
+ match msg.severity with
38
+ | MessageSeverity.information => str := "info:" ++ str
39
+ | MessageSeverity.warning => str := "warning:" ++ str
40
+ | MessageSeverity.error => str := "error:" ++ str
41
+ if str.isEmpty || str.back != '\n' then
42
+ str := str ++ "\n"
43
+ return str
44
+
45
+ /-- The decision made by a specification for a message. -/
46
+ inductive SpecResult
47
+ /-- Capture the message and check it matches the docstring. -/
48
+ | check
49
+ /-- Drop the message and delete it. -/
50
+ | drop
51
+ /-- Do not capture the message. -/
52
+ | pass
53
+
54
+ /-- The method to use when normalizing whitespace, after trimming. -/
55
+ inductive WhitespaceMode
56
+ /-- Exact equality. -/
57
+ | exact
58
+ /-- Equality after normalizing newlines into spaces. -/
59
+ | normalized
60
+ /-- Equality after collapsing whitespace into single spaces. -/
61
+ | lax
62
+
63
+ /-- Method to use when combining multiple messages. -/
64
+ inductive MessageOrdering
65
+ /-- Use the exact ordering of the produced messages. -/
66
+ | exact
67
+ /-- Sort the produced messages. -/
68
+ | sorted
69
+
70
+ def parseGuardMsgsFilterAction (action? : Option (TSyntax ``guardMsgsFilterAction)) :
71
+ CommandElabM SpecResult := do
72
+ if let some action := action? then
73
+ match action with
74
+ | `(guardMsgsFilterAction| check) => pure .check
75
+ | `(guardMsgsFilterAction| drop) => pure .drop
76
+ | `(guardMsgsFilterAction| pass) => pure .pass
77
+ | _ => throwUnsupportedSyntax
78
+ else
79
+ pure .check
80
+
81
+ def parseGuardMsgsFilterSeverity : TSyntax ``guardMsgsFilterSeverity β†’ CommandElabM (Message β†’ Bool)
82
+ | `(guardMsgsFilterSeverity| trace) => pure fun msg => msg.isTrace
83
+ | `(guardMsgsFilterSeverity| info) => pure fun msg => !msg.isTrace && msg.severity == .information
84
+ | `(guardMsgsFilterSeverity| warning) => pure fun msg => !msg.isTrace && msg.severity == .warning
85
+ | `(guardMsgsFilterSeverity| error) => pure fun msg => !msg.isTrace && msg.severity == .error
86
+ | `(guardMsgsFilterSeverity| all) => pure fun _ => true
87
+ | _ => throwUnsupportedSyntax
88
+
89
+ /-- Parses a `guardMsgsSpec`.
90
+ - No specification: check everything.
91
+ - With a specification: interpret the spec, and if nothing applies pass it through. -/
92
+ def parseGuardMsgsSpec (spec? : Option (TSyntax ``guardMsgsSpec)) :
93
+ CommandElabM (WhitespaceMode Γ— MessageOrdering Γ— (Message β†’ SpecResult)) := do
94
+ let elts ←
95
+ if let some spec := spec? then
96
+ match spec with
97
+ | `(guardMsgsSpec| ($[$elts:guardMsgsSpecElt],*)) => pure elts
98
+ | _ => throwUnsupportedSyntax
99
+ else
100
+ pure #[]
101
+ let mut whitespace : WhitespaceMode := .normalized
102
+ let mut ordering : MessageOrdering := .exact
103
+ let mut p? : Option (Message β†’ SpecResult) := none
104
+ let pushP (action : SpecResult) (msgP : Message β†’ Bool) (p? : Option (Message β†’ SpecResult))
105
+ (msg : Message) : SpecResult :=
106
+ if msgP msg then
107
+ action
108
+ else
109
+ (p?.getD fun _ => .pass) msg
110
+ for elt in elts.reverse do
111
+ match elt with
112
+ | `(guardMsgsSpecElt| $[$action?]? $sev) => p? := pushP (← parseGuardMsgsFilterAction action?) (← parseGuardMsgsFilterSeverity sev) p?
113
+ | `(guardMsgsSpecElt| whitespace := exact) => whitespace := .exact
114
+ | `(guardMsgsSpecElt| whitespace := normalized) => whitespace := .normalized
115
+ | `(guardMsgsSpecElt| whitespace := lax) => whitespace := .lax
116
+ | `(guardMsgsSpecElt| ordering := exact) => ordering := .exact
117
+ | `(guardMsgsSpecElt| ordering := sorted) => ordering := .sorted
118
+ | _ => throwUnsupportedSyntax
119
+ let defaultP := fun _ => .check
120
+ return (whitespace, ordering, p?.getD defaultP)
121
+
122
+ /-- An info tree node corresponding to a failed `#guard_msgs` invocation,
123
+ used for code action support. -/
124
+ structure GuardMsgFailure where
125
+ /-- The result of the nested command -/
126
+ res : String
127
+ deriving TypeName
128
+
129
+ /--
130
+ Makes trailing whitespace visible and protectes them against trimming by the editor, by appending
131
+ the symbol ⏎ to such a line (and also to any line that ends with such a symbol, to avoid
132
+ ambiguities in the case the message already had that symbol).
133
+ -/
134
+ def revealTrailingWhitespace (s : String) : String :=
135
+ s.replace "⏎\n" "⏎⏎\n" |>.replace "\t\n" "\t⏎\n" |>.replace " \n" " ⏎\n"
136
+
137
+ /- The inverse of `revealTrailingWhitespace` -/
138
+ def removeTrailingWhitespaceMarker (s : String) : String :=
139
+ s.replace "⏎\n" "\n"
140
+
141
+ /--
142
+ Applies a whitespace normalization mode.
143
+ -/
144
+ def WhitespaceMode.apply (mode : WhitespaceMode) (s : String) : String :=
145
+ match mode with
146
+ | .exact => s
147
+ | .normalized => s.replace "\n" " "
148
+ | .lax => String.intercalate " " <| (s.split Char.isWhitespace).filter (!Β·.isEmpty)
149
+
150
+ /--
151
+ Applies a message ordering mode.
152
+ -/
153
+ def MessageOrdering.apply (mode : MessageOrdering) (msgs : List String) : List String :=
154
+ match mode with
155
+ | .exact => msgs
156
+ | .sorted => msgs |>.toArray.qsort (Β· < Β·) |>.toList
157
+
158
+ @[builtin_command_elab Lean.guardMsgsCmd] def elabGuardMsgs : CommandElab
159
+ | `(command| $[$dc?:docComment]? #guard_msgs%$tk $(spec?)? in $cmd) => do
160
+ let expected : String := (← dc?.mapM (getDocStringText Β·)).getD ""
161
+ |>.trim |> removeTrailingWhitespaceMarker
162
+ let (whitespace, ordering, specFn) ← parseGuardMsgsSpec spec?
163
+ let initMsgs ← modifyGet fun st => (st.messages, { st with messages := {} })
164
+ -- do not forward snapshot as we don't want messages assigned to it to leak outside
165
+ withReader ({ Β· with snap? := none }) do
166
+ -- The `#guard_msgs` command is special-cased in `elabCommandTopLevel` to ensure linters only run once.
167
+ elabCommandTopLevel cmd
168
+ -- collect sync and async messages
169
+ let msgs := (← get).messages ++
170
+ (← get).snapshotTasks.foldl (Β· ++ Β·.get.getAll.foldl (Β· ++ Β·.diagnostics.msgLog) {}) {}
171
+ -- clear async messages as we don't want them to leak outside
172
+ modify ({ Β· with snapshotTasks := #[] })
173
+ let mut toCheck : MessageLog := .empty
174
+ let mut toPassthrough : MessageLog := .empty
175
+ for msg in msgs.toList do
176
+ if msg.isSilent then
177
+ continue
178
+ match specFn msg with
179
+ | .check => toCheck := toCheck.add msg
180
+ | .drop => pure ()
181
+ | pass => toPassthrough := toPassthrough.add msg
182
+ let strings ← toCheck.toList.mapM (messageToStringWithoutPos Β·)
183
+ let strings := ordering.apply strings
184
+ let res := "---\n".intercalate strings |>.trim
185
+ if whitespace.apply expected == whitespace.apply res then
186
+ -- Passed. Only put toPassthrough messages back on the message log
187
+ modify fun st => { st with messages := initMsgs ++ toPassthrough }
188
+ else
189
+ -- Failed. Put all the messages back on the message log and add an error
190
+ modify fun st => { st with messages := initMsgs ++ msgs }
191
+ let feedback :=
192
+ if guard_msgs.diff.get (← getOptions) then
193
+ let diff := Diff.diff (expected.split (Β· == '\n')).toArray (res.split (Β· == '\n')).toArray
194
+ Diff.linesToString diff
195
+ else res
196
+ logErrorAt tk m!"❌️ Docstring on `#guard_msgs` does not match generated message:\n\n{feedback}"
197
+ pushInfoLeaf (.ofCustomInfo { stx := ← getRef, value := Dynamic.mk (GuardMsgFailure.mk res) })
198
+ | _ => throwUnsupportedSyntax
199
+
200
+ open CodeAction Server RequestM in
201
+ /-- A code action which will update the doc comment on a `#guard_msgs` invocation. -/
202
+ @[builtin_command_code_action guardMsgsCmd]
203
+ def guardMsgsCodeAction : CommandCodeAction := fun _ _ _ node => do
204
+ let .node _ ts := node | return #[]
205
+ let res := ts.findSome? fun
206
+ | .node (.ofCustomInfo { stx, value }) _ => return (stx, (← value.get? GuardMsgFailure).res)
207
+ | _ => none
208
+ let some (stx, res) := res | return #[]
209
+ let doc ← readDoc
210
+ let eager := {
211
+ title := "Update #guard_msgs with tactic output"
212
+ kind? := "quickfix"
213
+ isPreferred? := true
214
+ }
215
+ pure #[{
216
+ eager
217
+ lazy? := some do
218
+ let some start := stx.getPos? true | return eager
219
+ let some tail := stx.setArg 0 mkNullNode |>.getPos? true | return eager
220
+ let res := revealTrailingWhitespace res
221
+ let newText := if res.isEmpty then
222
+ ""
223
+ else if res.length ≀ 100-7 && !res.contains '\n' then -- TODO: configurable line length?
224
+ s!"/-- {res} -/\n"
225
+ else
226
+ s!"/--\n{res}\n-/\n"
227
+ pure { eager with
228
+ edit? := some <|.ofTextEdit doc.versionedIdentifier {
229
+ range := doc.meta.text.utf8RangeToLspRange ⟨start, tail⟩
230
+ newText
231
+ }
232
+ }
233
+ }]
234
+
235
+ end Lean.Elab.Tactic.GuardMsgs
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Import.lean ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2019 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Sebastian Ullrich
5
+ -/
6
+ prelude
7
+ import Lean.Parser.Module
8
+ import Lean.CoreM
9
+
10
+ namespace Lean.Elab
11
+
12
+ abbrev HeaderSyntax := TSyntax ``Parser.Module.header
13
+
14
+ def HeaderSyntax.startPos (header : HeaderSyntax) : String.Pos :=
15
+ header.raw.getPos?.getD 0
16
+
17
+ def HeaderSyntax.isModule (header : HeaderSyntax) : Bool :=
18
+ !header.raw[0].isNone
19
+
20
+ def HeaderSyntax.imports (stx : HeaderSyntax) (includeInit : Bool := true) : Array Import :=
21
+ match stx with
22
+ | `(Parser.Module.header| $[module%$moduleTk]? $[prelude%$preludeTk]? $importsStx*) =>
23
+ let imports := if preludeTk.isNone && includeInit then #[{ module := `Init : Import }] else #[]
24
+ imports ++ importsStx.map fun
25
+ | `(Parser.Module.import| $[public%$publicTk]? $[meta%$metaTk]? import $[all%$allTk]? $n) =>
26
+ { module := n.getId, importAll := allTk.isSome
27
+ isExported := publicTk.isSome || moduleTk.isNone
28
+ isMeta := metaTk.isSome }
29
+ | _ => unreachable!
30
+ | _ => unreachable!
31
+
32
+ def HeaderSyntax.toModuleHeader (stx : HeaderSyntax) : ModuleHeader where
33
+ isModule := stx.isModule
34
+ imports := stx.imports
35
+
36
+ abbrev headerToImports := @HeaderSyntax.imports
37
+
38
+ def processHeaderCore
39
+ (startPos : String.Pos) (imports : Array Import) (isModule : Bool)
40
+ (opts : Options) (messages : MessageLog) (inputCtx : Parser.InputContext)
41
+ (trustLevel : UInt32 := 0) (plugins : Array System.FilePath := #[]) (leakEnv := false)
42
+ (mainModule := Name.anonymous) (arts : NameMap ImportArtifacts := {})
43
+ : IO (Environment Γ— MessageLog) := do
44
+ let level := if isModule then
45
+ if Elab.inServer.get opts then
46
+ .server
47
+ else
48
+ .exported
49
+ else
50
+ .private
51
+ let (env, messages) ← try
52
+ for i in imports do
53
+ if !isModule && i.importAll then
54
+ throw <| .userError "cannot use `import all` without `module`"
55
+ if i.importAll && mainModule.getRoot != i.module.getRoot then
56
+ throw <| .userError "cannot use `import all` across module path roots"
57
+ let env ←
58
+ importModules (leakEnv := leakEnv) (loadExts := true) (level := level)
59
+ imports opts trustLevel plugins arts
60
+ pure (env, messages)
61
+ catch e =>
62
+ let env ← mkEmptyEnvironment
63
+ let pos := inputCtx.fileMap.toPosition startPos
64
+ pure (env, messages.add { fileName := inputCtx.fileName, data := toString e, pos := pos })
65
+ return (env.setMainModule mainModule, messages)
66
+
67
+ /--
68
+ Elaborates the given header syntax into an environment.
69
+
70
+ If `mainModule` is not given, `Environment.setMainModule` should be called manually. This is a
71
+ backwards compatibility measure not compatible with the module system.
72
+ -/
73
+ @[inline] def processHeader
74
+ (header : HeaderSyntax)
75
+ (opts : Options) (messages : MessageLog) (inputCtx : Parser.InputContext)
76
+ (trustLevel : UInt32 := 0) (plugins : Array System.FilePath := #[]) (leakEnv := false)
77
+ (mainModule := Name.anonymous)
78
+ : IO (Environment Γ— MessageLog) := do
79
+ processHeaderCore header.startPos header.imports header.isModule
80
+ opts messages inputCtx trustLevel plugins leakEnv mainModule
81
+
82
+ def parseImports (input : String) (fileName : Option String := none) : IO (Array Import Γ— Position Γ— MessageLog) := do
83
+ let fileName := fileName.getD "<input>"
84
+ let inputCtx := Parser.mkInputContext input fileName
85
+ let (header, parserState, messages) ← Parser.parseHeader inputCtx
86
+ pure (headerToImports header, inputCtx.fileMap.toPosition parserState.pos, messages)
87
+
88
+ def printImports (input : String) (fileName : Option String) : IO Unit := do
89
+ let (deps, _, _) ← parseImports input fileName
90
+ for dep in deps do
91
+ let fname ← findOLean dep.module
92
+ IO.println fname
93
+
94
+ def printImportSrcs (input : String) (fileName : Option String) : IO Unit := do
95
+ let sp ← getSrcSearchPath
96
+ let (deps, _, _) ← parseImports input fileName
97
+ for dep in deps do
98
+ let fname ← findLean sp dep.module
99
+ IO.println fname
100
+
101
+ end Lean.Elab
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/Inductive.lean ADDED
@@ -0,0 +1,301 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2020 Microsoft Corporation. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+ Authors: Leonardo de Moura, Kyle Miller
5
+ -/
6
+ prelude
7
+ import Lean.Elab.MutualInductive
8
+
9
+ namespace Lean.Elab.Command
10
+ open Meta
11
+
12
+ /-
13
+ ```
14
+ def Lean.Parser.Command.Β«inductiveΒ» :=
15
+ leading_parser "inductive " >> declId >> optDeclSig >> optional ("where" <|> ":=") >> many ctor
16
+
17
+ def Lean.Parser.Command.classInductive :=
18
+ leading_parser atomic (group ("class " >> "inductive ")) >> declId >> optDeclSig >> optional ("where" <|> ":=") >> many ctor >> optDeriving
19
+ ```
20
+ -/
21
+ private def inductiveSyntaxToView (modifiers : Modifiers) (decl : Syntax) : TermElabM InductiveView := do
22
+ let isClass := decl.isOfKind ``Parser.Command.classInductive
23
+ let modifiers := if isClass then modifiers.addAttr { name := `class } else modifiers
24
+ let (binders, type?) := expandOptDeclSig decl[2]
25
+ let declId := decl[1]
26
+ let ⟨name, declName, levelNames⟩ ← Term.expandDeclId (← getCurrNamespace) (← Term.getLevelNames) declId modifiers
27
+ addDeclarationRangesForBuiltin declName modifiers.stx decl
28
+ let ctors ← decl[4].getArgs.mapM fun ctor => withRef ctor do
29
+ /-
30
+ ```
31
+ def ctor := leading_parser optional docComment >> "\n| " >> declModifiers >> rawIdent >> optDeclSig
32
+ ```
33
+ -/
34
+ let mut ctorModifiers ← elabModifiers ⟨ctor[2]⟩
35
+ if let some leadingDocComment := ctor[0].getOptional? then
36
+ if ctorModifiers.docString?.isSome then
37
+ logErrorAt leadingDocComment "duplicate doc string"
38
+ ctorModifiers := { ctorModifiers with docString? := some ⟨leadingDocComment⟩ }
39
+ if ctorModifiers.isPrivate && modifiers.isPrivate then
40
+ throwError "invalid 'private' constructor in a 'private' inductive datatype"
41
+ if ctorModifiers.isProtected && modifiers.isPrivate then
42
+ throwError "invalid 'protected' constructor in a 'private' inductive datatype"
43
+ checkValidCtorModifier ctorModifiers
44
+ let ctorName := ctor.getIdAt 3
45
+ let ctorName := declName ++ ctorName
46
+ let ctorName ← withRef ctor[3] <| applyVisibility ctorModifiers.visibility ctorName
47
+ let (binders, type?) := expandOptDeclSig ctor[4]
48
+ addDocString' ctorName ctorModifiers.docString?
49
+ addDeclarationRangesFromSyntax ctorName ctor ctor[3]
50
+ return { ref := ctor, declId := ctor[3], modifiers := ctorModifiers, declName := ctorName, binders := binders, type? := type? : CtorView }
51
+ let computedFields ← (decl[5].getOptional?.map (Β·[1].getArgs) |>.getD #[]).mapM fun cf => withRef cf do
52
+ return { ref := cf, modifiers := cf[0], fieldId := cf[1].getId, type := ⟨cf[3]⟩, matchAlts := ⟨cf[4]⟩ }
53
+ let classes ← getOptDerivingClasses decl[6]
54
+ if decl[3][0].isToken ":=" then
55
+ -- https://github.com/leanprover/lean4/issues/5236
56
+ withRef decl[0] <| Linter.logLintIf Linter.linter.deprecated decl[3]
57
+ "'inductive ... :=' has been deprecated in favor of 'inductive ... where'."
58
+ return {
59
+ ref := decl
60
+ shortDeclName := name
61
+ derivingClasses := classes
62
+ allowIndices := true
63
+ allowSortPolymorphism := true
64
+ declId, modifiers, isClass, declName, levelNames
65
+ binders, type?, ctors
66
+ computedFields
67
+ }
68
+
69
+ private def isInductiveFamily (numParams : Nat) (indFVar : Expr) : TermElabM Bool := do
70
+ let indFVarType ← inferType indFVar
71
+ forallTelescopeReducing indFVarType fun xs _ =>
72
+ return xs.size > numParams
73
+
74
+ private def getArrowBinderNames (type : Expr) : Array Name :=
75
+ go type #[]
76
+ where
77
+ go (type : Expr) (acc : Array Name) : Array Name :=
78
+ match type with
79
+ | .forallE n _ b _ => go b (acc.push n)
80
+ | .mdata _ b => go b acc
81
+ | _ => acc
82
+
83
+ /--
84
+ Replaces binder names in `type` with `newNames`.
85
+ Remark: we only replace the names for binder containing macroscopes.
86
+ -/
87
+ private def replaceArrowBinderNames (type : Expr) (newNames : Array Name) : Expr :=
88
+ go type 0
89
+ where
90
+ go (type : Expr) (i : Nat) : Expr :=
91
+ if h : i < newNames.size then
92
+ match type with
93
+ | .forallE n d b bi =>
94
+ if n.hasMacroScopes then
95
+ mkForall newNames[i] bi d (go b (i+1))
96
+ else
97
+ mkForall n bi d (go b (i+1))
98
+ | _ => type
99
+ else
100
+ type
101
+
102
+ /--
103
+ Reorders constructor arguments to improve the effectiveness of the `fixedIndicesToParams` method.
104
+
105
+ The idea is quite simple. Given a constructor type of the form
106
+ ```
107
+ (a₁ : A₁) β†’ ... β†’ (aβ‚™ : Aβ‚™) β†’ C b₁ ... bβ‚˜
108
+ ```
109
+ We try to find the longest prefix `b₁ ... bα΅’`, `i ≀ m` s.t.
110
+ - each `bβ‚–` is in `{a₁, ..., aβ‚™}`
111
+ - each `bβ‚–` only depends on variables in `{b₁, ..., bₖ₋₁}`
112
+
113
+ Then, it moves this prefix `b₁ ... bα΅’` to the front.
114
+
115
+ Remark: We only reorder implicit arguments that have macroscopes. See issue #1156.
116
+ The macroscope test is an approximation, we could have restricted ourselves to auto-implicit arguments.
117
+ -/
118
+ private def reorderCtorArgs (ctorType : Expr) : MetaM Expr := do
119
+ forallTelescopeReducing ctorType fun as type => do
120
+ /- `type` is of the form `C ...` where `C` is the inductive datatype being defined. -/
121
+ let bs := type.getAppArgs
122
+ let mut as := as
123
+ let mut bsPrefix := #[]
124
+ for b in bs do
125
+ unless b.isFVar && as.contains b do
126
+ break
127
+ let localDecl ← getFVarLocalDecl b
128
+ if localDecl.binderInfo.isExplicit then
129
+ break
130
+ unless localDecl.userName.hasMacroScopes do
131
+ break
132
+ if (← localDeclDependsOnPred localDecl fun fvarId => as.any fun p => p.fvarId! == fvarId) then
133
+ break
134
+ bsPrefix := bsPrefix.push b
135
+ as := as.erase b
136
+ if bsPrefix.isEmpty then
137
+ return ctorType
138
+ else
139
+ let r ← mkForallFVars (bsPrefix ++ as) type
140
+ /- `r` already contains the resulting type.
141
+ To be able to produce better error messages, we copy the first `bsPrefix.size` binder names from `C` to `r`.
142
+ This is important when some of constructor parameters were inferred using the auto-bound implicit feature.
143
+ For example, in the following declaration.
144
+ ```
145
+ inductive Member : Ξ± β†’ List Ξ± β†’ Type u
146
+ | head : Member a (a::as)
147
+ | tail : Member a bs β†’ Member a (b::bs)
148
+ ```
149
+ if we do not copy the binder names
150
+ ```
151
+ #check @Member.head
152
+ ```
153
+ produces `@Member.head : {x : Type u_1} β†’ {a : x} β†’ {as : List x} β†’ Member a (a :: as)`
154
+ which is correct, but a bit confusing. By copying the binder names, we obtain
155
+ `@Member.head : {Ξ± : Type u_1} β†’ {a : Ξ±} β†’ {as : List Ξ±} β†’ Member a (a :: as)`
156
+ -/
157
+ let C := type.getAppFn
158
+ let binderNames := getArrowBinderNames (← instantiateMVars (← inferType C))
159
+ return replaceArrowBinderNames r binderNames[*...bsPrefix.size]
160
+
161
+ /--
162
+ Elaborate constructor types.
163
+
164
+ Remark: we check whether the resulting type is correct, and the parameter occurrences are consistent, but
165
+ we currently do not check for:
166
+ - Positivity (it is a rare failure, and the kernel already checks for it).
167
+ - Universe constraints (the kernel checks for it).
168
+ -/
169
+ private def elabCtors (indFVars : Array Expr) (params : Array Expr) (r : ElabHeaderResult) : TermElabM (List Constructor) :=
170
+ withRef r.view.ref do
171
+ withExplicitToImplicit params do
172
+ let indFVar := r.indFVar
173
+ let indFamily ← isInductiveFamily params.size indFVar
174
+ r.view.ctors.toList.mapM fun ctorView =>
175
+ Term.withAutoBoundImplicit <| Term.elabBinders ctorView.binders.getArgs fun ctorParams =>
176
+ withRef ctorView.ref do
177
+ let elabCtorType : TermElabM Expr := do
178
+ match ctorView.type? with
179
+ | none =>
180
+ if indFamily then
181
+ throwError "Missing resulting type for constructor '{ctorView.declName}': \
182
+ Its resulting type must be specified because it is part of an inductive family declaration"
183
+ return mkAppN indFVar params
184
+ | some ctorType =>
185
+ let type ← Term.elabType ctorType
186
+ trace[Elab.inductive] "elabType {ctorView.declName} : {type} "
187
+ Term.synthesizeSyntheticMVars (postpone := .yes)
188
+ let type ← instantiateMVars type
189
+ let type ← checkParamOccs type
190
+ forallTelescopeReducing type fun _ resultingType => do
191
+ unless resultingType.getAppFn == indFVar do
192
+ throwUnexpectedResultingTypeMismatch resultingType indFVar ctorView.declName ctorType
193
+ unless (← isType resultingType) do
194
+ throwUnexpectedResultingTypeNotType resultingType ctorView.declName ctorType
195
+ return type
196
+ let type ← elabCtorType
197
+ Term.synthesizeSyntheticMVarsNoPostponing
198
+ let ctorParams ← Term.addAutoBoundImplicits ctorParams (ctorView.declId.getTailPos? (canonicalOnly := true))
199
+ let except (mvarId : MVarId) := ctorParams.any fun ctorParam => ctorParam.isMVar && ctorParam.mvarId! == mvarId
200
+ /-
201
+ We convert metavariables in the resulting type into extra parameters. Otherwise, we would not be able to elaborate
202
+ declarations such as
203
+ ```
204
+ inductive Palindrome : List Ξ± β†’ Prop where
205
+ | nil : Palindrome [] -- We would get an error here saying "failed to synthesize implicit argument" at `@List.nil ?m`
206
+ | single : (a : Ξ±) β†’ Palindrome [a]
207
+ | sandwich : (a : Ξ±) β†’ Palindrome as β†’ Palindrome ([a] ++ as ++ [a])
208
+ ```
209
+ We used to also collect unassigned metavariables on `ctorParams`, but it produced counterintuitive behavior.
210
+ For example, the following declaration used to be accepted.
211
+ ```
212
+ inductive Foo
213
+ | bar (x)
214
+
215
+ #check Foo.bar
216
+ -- @Foo.bar : {x : Sort u_1} β†’ x β†’ Foo
217
+ ```
218
+ which is also inconsistent with the behavior of auto implicits in definitions. For example, the following example was never accepted.
219
+ ```
220
+ def bar (x) := 1
221
+ ```
222
+ -/
223
+ let extraCtorParams ← Term.collectUnassignedMVars (← instantiateMVars type) #[] except
224
+ trace[Elab.inductive] "extraCtorParams: {extraCtorParams}"
225
+ /- We must abstract `extraCtorParams` and `ctorParams` simultaneously to make
226
+ sure we do not create auxiliary metavariables. -/
227
+ let type ← mkForallFVars (extraCtorParams ++ ctorParams) type
228
+ let type ← reorderCtorArgs type
229
+ let type ← mkForallFVars params type
230
+ trace[Elab.inductive] "{ctorView.declName} : {type}"
231
+ return { name := ctorView.declName, type }
232
+ where
233
+ /--
234
+ Ensures that the arguments to recursive occurrences of the type family being defined match the
235
+ parameters from the inductive definition.
236
+ -/
237
+ checkParamOccs (ctorType : Expr) : MetaM Expr :=
238
+ let visit (e : Expr) : StateT (List Expr) MetaM TransformStep := do
239
+ let f := e.getAppFn
240
+ if indFVars.contains f then
241
+ let mut args := e.getAppArgs
242
+ -- Prefer throwing an "argument mismatch" error rather than a "missing parameter" one
243
+ for i in [:min args.size params.size] do
244
+ let param := params[i]!
245
+ let arg := args[i]!
246
+ unless (← isDefEq param arg) do
247
+ let (arg, param) ← addPPExplicitToExposeDiff arg param
248
+ let msg := m!"Mismatched inductive type parameter in{indentExpr e}\nThe provided argument\
249
+ {indentExpr arg}\nis not definitionally equal to the expected parameter{indentExpr param}"
250
+ let noteMsg := m!"The value of parameter '{param}' must be fixed throughout the inductive \
251
+ declaration. Consider making this parameter an index if it must vary."
252
+ throwNamedError lean.inductiveParamMismatch (msg ++ .note noteMsg)
253
+ args := args.set! i param
254
+ unless args.size β‰₯ params.size do
255
+ let expected := mkAppN f params
256
+ let containingExprMsg := (← get).head?.map toMessageData |>.getD m!"<missing>"
257
+ let msg :=
258
+ m!"Missing parameter(s) in occurrence of inductive type: In the expression{indentD containingExprMsg}\n\
259
+ found{indentExpr e}\nbut expected all parameters to be specified:{indentExpr expected}"
260
+ let noteMsg :=
261
+ m!"All occurrences of an inductive type in the types of its constructors must specify its \
262
+ fixed parameters. Only indices can be omitted in a partial application of the type constructor."
263
+ throwNamedError lean.inductiveParamMissing (msg ++ .note noteMsg)
264
+ return TransformStep.done (mkAppN f args)
265
+ else
266
+ modify fun es => e :: es
267
+ return .continue
268
+ let popContainingExpr (e : Expr) : StateT (List Expr) MetaM TransformStep := do
269
+ modify fun es => es.drop 1
270
+ return .done e
271
+ transform ctorType (pre := visit) (post := popContainingExpr) |>.run' [ctorType]
272
+
273
+ throwUnexpectedResultingTypeMismatch (resultingType indFVar : Expr) (declName : Name) (ctorType : Syntax) := do
274
+ let lazyAppMsg := MessageData.ofLazyM do
275
+ if let some fvarId := indFVar.fvarId? then
276
+ if let some decl := (← getLCtx).find? fvarId then
277
+ if (← whnfD decl.type).isForall then
278
+ return m!" an application of"
279
+ return m!""
280
+ throwNamedErrorAt ctorType lean.ctorResultingTypeMismatch "Unexpected resulting type for constructor '{declName}': \
281
+ Expected{lazyAppMsg}{indentExpr indFVar}\nbut found{indentExpr resultingType}"
282
+
283
+ throwUnexpectedResultingTypeNotType (resultingType : Expr) (declName : Name) (ctorType : Syntax) := do
284
+ let lazyMsg := MessageData.ofLazyM do
285
+ let resultingTypeType ← inferType resultingType
286
+ return indentExpr resultingTypeType
287
+ throwNamedErrorAt ctorType lean.ctorResultingTypeMismatch "Unexpected resulting type for constructor '{declName}': \
288
+ Expected a type, but found{indentExpr resultingType}\nof type{lazyMsg}"
289
+
290
+ @[builtin_inductive_elab Lean.Parser.Command.inductive, builtin_inductive_elab Lean.Parser.Command.classInductive]
291
+ def elabInductiveCommand : InductiveElabDescr where
292
+ mkInductiveView (modifiers : Modifiers) (stx : Syntax) := do
293
+ let view ← inductiveSyntaxToView modifiers stx
294
+ return {
295
+ view
296
+ elabCtors := fun rs r params => do
297
+ let ctors ← elabCtors (rs.map (Β·.indFVar)) params r
298
+ return { ctors }
299
+ }
300
+
301
+ end Lean.Elab.Command
backend/core/leanprover--lean4---v4.22.0/src/lean/Lean/Elab/InfoTree.lean ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ /-
2
+ Copyright (c) 2020 Wojciech Nawrocki. All rights reserved.
3
+ Released under Apache 2.0 license as described in the file LICENSE.
4
+
5
+ Authors: Wojciech Nawrocki, Leonardo de Moura, Sebastian Ullrich
6
+ -/
7
+ prelude
8
+ import Lean.Elab.InfoTree.Types
9
+ import Lean.Elab.InfoTree.Main