-
Notifications
You must be signed in to change notification settings - Fork 330
/
AssertExists.lean
68 lines (55 loc) · 2.72 KB
/
AssertExists.lean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
/-
Copyright (c) 2022 Scott Morrison. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Patrick Massot, Scott Morrison
-/
import Lean.Elab.Command
/-!
# User commands for assert the (non-)existence of declaration or instances.
These commands are used to enforce the independence of different parts of mathlib.
## TODO
Potentially after the port reimplement the mathlib 3 linters to check that declarations asserted
about do eventually exist.
Implement `assert_instance` and `assert_no_instance`
-/
section
open Lean Elab Meta Command
/--
`assert_exists n` is a user command that asserts that a declaration named `n` exists
in the current import scope.
Be careful to use names (e.g. `Rat`) rather than notations (e.g. `ℚ`).
-/
elab "assert_exists " n:ident : command => do
-- this throws an error if the user types something ambiguous or
-- something that doesn't exist, otherwise succeeds
let _ ← liftCoreM <| realizeGlobalConstNoOverloadWithInfo n
/--
`assert_not_exists n` is a user command that asserts that a declaration named `n` *does not exist*
in the current import scope.
Be careful to use names (e.g. `Rat`) rather than notations (e.g. `ℚ`).
It may be used (sparingly!) in mathlib to enforce plans that certain files
are independent of each other.
If you encounter an error on an `assert_not_exists` command while developing mathlib,
it is probably because you have introduced new import dependencies to a file.
In this case, you should refactor your work
(for example by creating new files rather than adding imports to existing files).
You should *not* delete the `assert_not_exists` statement without careful discussion ahead of time.
-/
elab "assert_not_exists " n:ident : command => do
let decl ← try liftCoreM <| realizeGlobalConstNoOverloadWithInfo n catch _ => return
let env ← getEnv
let c ← mkConstWithLevelParams decl
let msg ← (do
let mut some idx := env.getModuleIdxFor? decl
| pure m!"Declaration {c} is defined in this file."
let mut msg := m!"Declaration {c} is not allowed to be imported by this file.\n\
It is defined in {env.header.moduleNames[idx.toNat]!},"
for i in [idx.toNat+1:env.header.moduleData.size] do
if env.header.moduleData[i]!.imports.any (·.module == env.header.moduleNames[idx.toNat]!) then
idx := i
msg := msg ++ m!"\n which is imported by {env.header.moduleNames[i]!},"
pure <| msg ++ m!"\n which is imported by this file.")
throw <| .error n m!"{msg}\n\n\
These invariants are maintained by `assert_not_exists` statements, \
and exist in order to ensure that \"complicated\" parts of the library \
are not accidentally introduced as dependencies of \"simple\" parts of the library."