Skip to content
This repository was archived by the owner on Jul 24, 2024. It is now read-only.

Commit 173e70a

Browse files
robertylewismergify[bot]
authored andcommitted
feat(tactic/lint): rename and refactor sanity_check (#1556)
* chore(*): rename sanity_check to lint * rename sanity_check files to lint * refactor(tactic/lint): use attributes to add new linters * feat(tactic/lint): restrict which linters are run * doc(tactic/lint): document * doc(tactic/lint): document list_linters * chore(tactic/doc_blame): turn doc_blame into a linter * remove doc_blame import * fix(test/lint) * feat(meta/rb_map): add name_set.insert_list * feat(tactic/lint): better control over which linters are run * ignore instances in doc_blame * update lint documentation * minor refactor * correct docs * correct command doc strings * doc rb_map.lean * consistently use key/value * fix command doc strings
1 parent ee398b6 commit 173e70a

File tree

11 files changed

+477
-344
lines changed

11 files changed

+477
-344
lines changed

docs/tactics.md

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,30 +1137,39 @@ Here too, the `reassoc` attribute can be used instead. It works well when combin
11371137
```lean
11381138
attribute [simp, reassoc] some_class.bar
11391139
```
1140-
### sanity_check
1140+
### lint
11411141
User commands to spot common mistakes in the code
11421142

1143-
* `#sanity_check`: check all declarations in the current file
1144-
* `#sanity_check_mathlib`: check all declarations in mathlib (so excluding core or other projects,
1143+
* `#lint`: check all declarations in the current file
1144+
* `#lint_mathlib`: check all declarations in mathlib (so excluding core or other projects,
11451145
and also excluding the current file)
1146-
* `#sanity_check_all`: check all declarations in the environment (the current file and all
1146+
* `#lint_all`: check all declarations in the environment (the current file and all
11471147
imported files)
11481148

1149-
Currently this will check for
1149+
Five linters are run by default:
1150+
1. `unused_arguments` checks for unused arguments in declarations
1151+
2. `def_lemma` checks whether a declaration is incorrectly marked as a def/lemma
1152+
3. `dup_namespce` checks whether a namespace is duplicated in the name of a declaration
1153+
4. `illegal_constant` checks whether ≥/> is used in the declaration
1154+
5. `doc_blame` checks for missing doc strings on definitions and constants.
11501155

1151-
1. unused arguments in declarations,
1152-
2. whether a declaration is incorrectly marked as a def/lemma,
1153-
3. whether a namespace is duplicated in the name of a declaration
1154-
4. whether ≥/> is used in the declaration
1156+
A sixth linter, `doc_blame_thm`, checks for missing doc strings on lemmas and theorems.
1157+
This is not run by default.
11551158

1156-
You can append a `-` to any command (e.g. `#sanity_check_mathlib-`) to omit the slow tests (4).
1159+
The command `#list_linters` prints a list of the names of all available linters.
11571160

1158-
You can customize the performed checks like this:
1159-
```lean
1160-
meta def my_check (d : declaration) : tactic (option string) :=
1161-
return $ if d.to_name = `foo then some "gotcha!" else none
1162-
run_cmd sanity_check tt [(my_check, "found nothing", "found something")] >>= trace
1163-
```
1161+
You can append a `-` to any command (e.g. `#lint_mathlib-`) to omit the slow tests (4).
1162+
1163+
You can append a sequence of linter names to any command to run extra tests, in addition to the
1164+
default ones. e.g. `#lint doc_blame_thm` will run all default tests and `doc_blame_thm`.
1165+
1166+
You can append `only name1 name2 ...` to any command to run a subset of linters, e.g.
1167+
`#lint only unused_arguments`
1168+
1169+
You can add custom linters by defining a term of type `linter` in the `linter` namespace.
1170+
A linter defined with the name `linter.my_new_check` can be run with `#lint my_new_check`
1171+
or `lint only my_new_check`.
1172+
If you add the attribute `@[linter]` to `linter.my_new_check` it will run by default.
11641173

11651174
### lift
11661175

@@ -1195,12 +1204,12 @@ Lift an expression to another type.
11951204

11961205
### import_private
11971206

1198-
`import_private foo from bar` finds a private declaration `foo` in the same file as `bar` and creates a
1199-
local notation to refer to it.
1200-
1207+
`import_private foo from bar` finds a private declaration `foo` in the same file as `bar` and creates a
1208+
local notation to refer to it.
1209+
12011210
`import_private foo`, looks for `foo` in all (imported) files.
12021211

1203-
When possible, make `foo` non-private rather than using this feature.
1212+
When possible, make `foo` non-private rather than using this feature.
12041213

12051214
### default_dec_tac'
12061215

src/category/functor.lean

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Author: Simon Hudon
55
66
Standard identity and composition functors
77
-/
8-
import tactic.ext tactic.sanity_check category.basic
8+
import tactic.ext tactic.lint category.basic
99

1010
universe variables u v w
1111

@@ -42,7 +42,7 @@ def id.mk {α : Sort u} : α → id α := id
4242

4343
namespace functor
4444

45-
@[sanity_skip] def const (α : Type*) (β : Type*) := α
45+
@[nolint] def const (α : Type*) (β : Type*) := α
4646

4747
@[pattern] def const.mk {α β} (x : α) : const α β := x
4848

@@ -54,7 +54,7 @@ namespace const
5454

5555
protected lemma ext {α β} {x y : const α β} (h : x.run = y.run) : x = y := h
5656

57-
@[sanity_skip] protected def map {γ α β} (f : α → β) (x : const γ β) : const γ α := x
57+
@[nolint] protected def map {γ α β} (f : α → β) (x : const γ β) : const γ α := x
5858

5959
instance {γ} : functor (const γ) :=
6060
{ map := @const.map γ }

src/measure_theory/l1_space.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ assume hfi hgi,
4545
... < ⊤ : add_lt_top.2 ⟨hfi, hgi⟩
4646

4747
-- We don't need `f` to be measurable here, but it's easier to have a uniform API
48-
@[sanity_skip]
48+
@[nolint]
4949
lemma lintegral_nnnorm_neg {f : α → γ} (hf : measurable f) :
5050
(∫⁻ (a : α), ↑(nnnorm ((-f) a))) = ∫⁻ (a : α), ↑(nnnorm ((f) a)) :=
5151
lintegral_congr_ae $ by { filter_upwards [], simp }

src/meta/rb_map.lean

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,62 @@
22
Copyright (c) 2018 Robert Y. Lewis. All rights reserved.
33
Released under Apache 2.0 license as described in the file LICENSE.
44
Author: Robert Y. Lewis
5-
6-
Additional operations on native rb_maps and rb_sets.
75
-/
86
import data.option.defs
97

8+
/-!
9+
# rb_map
10+
11+
This file defines additional operations on native rb_maps and rb_sets.
12+
These structures are defined in core in `init.meta.rb_map`. They are meta objects,
13+
and are generally the most efficient dictionary structures to use for pure metaprogramming right now.
14+
-/
15+
1016
namespace native
1117
namespace rb_set
1218

19+
/-- `filter s P` returns the subset of elements of `s` satisfying `P`. -/
1320
meta def filter {key} (s : rb_set key) (P : key → bool) : rb_set key :=
1421
s.fold s (λ a m, if P a then m else m.erase a)
1522

23+
/-- `mfilter s P` returns the subset of elements of `s` satisfying `P`,
24+
where the check `P` is monadic. -/
1625
meta def mfilter {m} [monad m] {key} (s : rb_set key) (P : key → m bool) : m (rb_set key) :=
1726
s.fold (pure s) (λ a m,
1827
do x ← m,
1928
mcond (P a) (pure x) (pure $ x.erase a))
2029

30+
/-- `union s t` returns an rb_set containing every element that appears in either `s` or `t`. -/
2131
meta def union {key} (s t : rb_set key) : rb_set key :=
2232
s.fold t (λ a t, t.insert a)
2333

2434
end rb_set
2535

2636
namespace rb_map
2737

28-
meta def find_def {α β} (x : β) (m : rb_map α β) (k : α) :=
29-
(m.find k).get_or_else x
38+
/-- `find_def default m k` returns the value corresponding to `k` in `m`, if it exists.
39+
Otherwise it returns `default`. -/
40+
meta def find_def {key value} (default : value) (m : rb_map key value) (k : key) :=
41+
(m.find k).get_or_else default
3042

31-
meta def insert_cons {α β} [has_lt α] (k : α) (x : β) (m : rb_map α (list β)) : rb_map α (list β) :=
43+
/-- `insert_cons k x m` adds `x` to the list corresponding to key `k`. -/
44+
meta def insert_cons {key value} [has_lt key] (k : key) (x : value) (m : rb_map key (list value)) :
45+
rb_map key (list value) :=
3246
m.insert k (x :: m.find_def [] k)
3347

34-
meta def ifind {α β} [inhabited β] (m : rb_map α β) (a : α) : β :=
35-
(m.find a).iget
48+
/-- `ifind m key` returns the value corresponding to `key` in `m`, if it exists.
49+
Otherwise it returns the default value of `value`. -/
50+
meta def ifind {key value} [inhabited value] (m : rb_map key value) (k : key) : value :=
51+
(m.find k).iget
3652

37-
meta def zfind {α β} [has_zero β] (m : rb_map α β) (a : α) : β :=
38-
(m.find a).get_or_else 0
53+
/-- `zfind m key` returns the value corresponding to `key` in `m`, if it exists.
54+
Otherwise it returns 0. -/
55+
meta def zfind {key value} [has_zero value] (m : rb_map key value) (k : key) : value :=
56+
(m.find k).get_or_else 0
3957

40-
meta def add {α β} [has_add β] [has_zero β] [decidable_eq β] (m1 m2 : rb_map α β) : rb_map α β :=
58+
/-- Returns the pointwise sum of `m1` and `m2`, treating nonexistent values as 0. -/
59+
meta def add {key value} [has_add value] [has_zero value] [decidable_eq value]
60+
(m1 m2 : rb_map key value) : rb_map key value :=
4161
m1.fold m2
4262
(λ n v m,
4363
let nv := v + m2.zfind n in
@@ -46,15 +66,19 @@ m1.fold m2
4666
variables {m : TypeType*} [monad m]
4767
open function
4868

69+
/-- `mfilter P s` filters `s` by the monadic predicate `P` on keys and values. -/
4970
meta def mfilter {key val} [has_lt key] [decidable_rel ((<) : key → key → Prop)]
5071
(P : key → val → m bool) (s : rb_map key val) : m (rb_map.{0 0} key val) :=
5172
rb_map.of_list <$> s.to_list.mfilter (uncurry P)
5273

74+
/-- `mmap f s` maps the monadic function `f` over values in `s`. -/
5375
meta def mmap {key val val'} [has_lt key] [decidable_rel ((<) : key → key → Prop)]
5476
(f : val → m val') (s : rb_map key val) : m (rb_map.{0 0} key val') :=
5577
rb_map.of_list <$> s.to_list.mmap (λ ⟨a,b⟩, prod.mk a <$> f b)
5678

57-
meta def scale {α β} [has_lt α] [decidable_rel ((<) : α → α → Prop)] [has_mul β] (b : β) (m : rb_map α β) : rb_map α β :=
79+
/-- `scale b m` multiplies every value in `m` by `b`. -/
80+
meta def scale {key value} [has_lt key] [decidable_rel ((<) : key → key → Prop)] [has_mul value]
81+
(b : value) (m : rb_map key value) : rb_map key value :=
5882
m.map ((*) b)
5983

6084
section
@@ -85,21 +109,31 @@ end rb_lmap
85109
end native
86110

87111
namespace name_set
112+
113+
/-- `filter P s` returns the subset of elements of `s` satisfying `P`. -/
88114
meta def filter (P : name → bool) (s : name_set) : name_set :=
89115
s.fold s (λ a m, if P a then m else m.erase a)
90116

117+
/-- `mfilter P s` returns the subset of elements of `s` satisfying `P`,
118+
where the check `P` is monadic. -/
91119
meta def mfilter {m} [monad m] (P : name → m bool) (s : name_set) : m name_set :=
92120
s.fold (pure s) (λ a m,
93121
do x ← m,
94122
mcond (P a) (pure x) (pure $ x.erase a))
95123

124+
/-- `mmap f s` maps the monadic function `f` over values in `s`. -/
96125
meta def mmap {m} [monad m] (f : name → m name) (s : name_set) : m name_set :=
97126
s.fold (pure mk_name_set) (λ a m,
98127
do x ← m,
99128
b ← f a,
100129
(pure $ x.insert b))
101130

131+
/-- `union s t` returns an rb_set containing every element that appears in either `s` or `t`. -/
102132
meta def union (s t : name_set) : name_set :=
103133
s.fold t (λ a t, t.insert a)
104134

135+
/-- `insert_list s l` inserts every element of `l` into `s`. -/
136+
meta def insert_list (s : name_set) (l : list name) : name_set :=
137+
l.foldr (λ n s', s'.insert n) s
138+
105139
end name_set

src/tactic/basic.lean

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import
33
tactic.cache
44
tactic.converter.interactive
55
tactic.core
6-
tactic.doc_blame
76
tactic.ext
87
tactic.generalize_proofs
98
tactic.interactive
@@ -16,7 +15,7 @@ import
1615
tactic.replacer
1716
tactic.restate_axiom
1817
tactic.rewrite
19-
tactic.sanity_check
18+
tactic.lint
2019
tactic.simpa
2120
tactic.simps
2221
tactic.split_ifs

src/tactic/core.lean

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ do nm ← mk_fresh_name,
106106
return $ `user__ ++ nm.pop_prefix.sanitize_name ++ `user__
107107

108108

109-
/-- Checks whether n' has attribute n. -/
109+
/-- `has_attribute n n'` checks whether n' has attribute n. -/
110110
meta def has_attribute' : name → name → tactic bool | n n' :=
111111
succeeds (has_attribute n n')
112112

src/tactic/doc_blame.lean

Lines changed: 0 additions & 33 deletions
This file was deleted.

src/tactic/interactive.lean

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Copyright (c) 2017 Mario Carneiro. All rights reserved.
44
Released under Apache 2.0 license as described in the file LICENSE.
55
Authors: Mario Carneiro, Simon Hudon, Sebastien Gouezel, Scott Morrison
66
-/
7-
import tactic.sanity_check
7+
import tactic.lint
88

99
open lean
1010
open lean.parser
@@ -132,7 +132,7 @@ private meta def generalize_arg_p_aux : pexpr → parser (pexpr × name)
132132
private meta def generalize_arg_p : parser (pexpr × name) :=
133133
with_desc "expr = id" $ parser.pexpr 0 >>= generalize_arg_p_aux
134134

135-
@[sanity_skip] lemma {u} generalize_a_aux {α : Sort u}
135+
@[nolint] lemma {u} generalize_a_aux {α : Sort u}
136136
(h : ∀ x : Sort u, (α → x) → x) : α := h α id
137137

138138
/--

0 commit comments

Comments
 (0)