@@ -16,6 +16,7 @@ This file defines several small linters:
16
16
- `doc_blame_thm` checks that every theorem has a documentation string (not enabled by default).
17
17
- `def_lemma` checks that a declaration is a lemma iff its type is a proposition.
18
18
- `check_type` checks that the statement of a declaration is well-typed.
19
+ - `check_univs` checks that that there are no bad `max u v` universe levels.
19
20
-/
20
21
21
22
open tactic expr
@@ -212,8 +213,6 @@ meta def linter.doc_blame_thm : linter :=
212
213
errors_found := " THEOREMS ARE MISSING DOCUMENTATION STRINGS:" ,
213
214
is_fast := ff }
214
215
215
-
216
-
217
216
/-!
218
217
## Linter for correct usage of `lemma`/`def`
219
218
-/
@@ -249,6 +248,10 @@ has been used. -/
249
248
250
249
attribute [nolint def_lemma] classical.dec classical.dec_pred classical.dec_rel classical.dec_eq
251
250
251
+ /-!
252
+ ## Linter that checks whether declarations are well-typed
253
+ -/
254
+
252
255
/-- Checks whether the statement of a declaration is well-typed. -/
253
256
meta def check_type (d : declaration) : tactic (option string) :=
254
257
(type_check d.type >> return none) <|> return " The statement doesn't type-check"
@@ -266,3 +269,53 @@ Some definitions in the statement are marked `@[irreducible]`, which means that
266
269
" or `@[semireducible]`. This can especially cause problems with type class inference or " ++
267
270
" `@[simps]`." ,
268
271
is_fast := tt }
272
+
273
+ /-!
274
+ ## Linter for universe parameters
275
+ -/
276
+
277
+ open native
278
+
279
+ /--
280
+ The good parameters are the parameters that occur somewhere in the `rb_set` as a singleton or
281
+ (recursively) with only other good parameters.
282
+ All other parameters in the `rb_set` are bad.
283
+ -/
284
+ meta def bad_params : rb_set (list name) → list name | l :=
285
+ let good_levels : name_set :=
286
+ l.fold mk_name_set $ λ us prev, if us.length = 1 then prev.insert us.head else prev in
287
+ if good_levels.empty then
288
+ l.fold [] list.union
289
+ else bad_params $ rb_set.of_list $ l.to_list.map $ λ us, us.filter $ λ nm, !good_levels.contains nm
290
+
291
+ /--
292
+ Checks whether all universe levels `u` in `d` are "good".
293
+ This means that `u` either occurs in a `level` of `d` by itself, or (recursively)
294
+ with only other good levels.
295
+ When this fails, usually this means that there is a level `max u v`, where neither `u` nor `v`
296
+ occur by themselves in a level. It is ok if *one* of `u` or `v` never occurs alone. For example,
297
+ `(α : Type u) (β : Type (max u v))` is a occasionally useful method of saying that `β` lives in
298
+ a higher universe level than `α`.
299
+ -/
300
+ meta def check_univs (d : declaration) : tactic (option string) := do
301
+ let l := d.type.univ_params_grouped.union d.value.univ_params_grouped,
302
+ let bad := bad_params l,
303
+ if bad.empty then return none else return $ some $ " universes " ++ to_string bad ++
304
+ " only occur together."
305
+
306
+ /-- A linter for checking that there are no bad `max u v` universe levels. -/
307
+ @[linter]
308
+ meta def linter.check_univs : linter :=
309
+ { test := check_univs,
310
+ auto_decls := tt,
311
+ no_errors_found :=
312
+ " All declaratations have good universe levels." ,
313
+ errors_found := " THE STATEMENTS OF THE FOLLOWING DECLARATIONS HAVE BAD UNIVERSE LEVELS. " ++
314
+ " This usually means that there is a `max u v` in the declaration where neither `u` nor `v` " ++
315
+ " occur by themselves. Solution: Find the type (or type bundled with data) that has this " ++
316
+ " universe argument and provide the universe level explicitly. If this happens in an implicit " ++
317
+ " argument of the declaration, a better solution is to move this argument to a `variables` " ++
318
+ " command (where the universe level can be kept implicit).
319
+ Note: if the linter flags an automatically generated declaration `xyz._proof_i`, it means that
320
+ the universe problem is with `xyz` itself (even if the linter doesn't flag `xyz`)" ,
321
+ is_fast := tt }
0 commit comments