This PR makes the equational theorems of non-exposed defs private. If the author of a module chose not to expose the body of their function, then they likely don't want that implementation to leak through equational theorems. Helps with #8419. There is some amount of incidential complexity due to how `private` works in lean, by mangling the name: lots of code paths that need now do the right thing™ about private and non-private names, including the whole reserved name machinery. So this includes a number of refactorings: * The logic for calculating an equational theorem name (or similar) is now done by a single function, `mkEqLikeNameFor`, rather than all over the place. * Since the name of the equational theorem now depends on the current context (in particular whether it’s a proper module, or a non-module file), the forward map from declaration to equational theorem doesn’t quite work anymore. This map is deleted; the list of equational theorems are now always found by looking for declaration of the expected names (`alreadyGenerated). If users define such theorems themselves (and make it past the “do not allow reserved names to be declared”) they get to keep both pieces. * Because this map was deleted, mathlib’s `eqns` command can no longer easily warn if equational lemmas have already been generated too early (adaption branch exists). But in general I think lean could provide a more principled way of supporting custom unfold lemmas, and ideally the whole equational theorem machinery is just using that. * The ReservedNamePredicate is used by `resolveExact`, so we need to make sure that it returns the right name, including privateness. It is not ok to just reserve both the private and non-private name but then later in the ReservedNameAction produce just one of the two. * We create `foo.def_eq` eagerly for well-founded recursion. This is needed because we need feed in the proof of the rewriting done by `wf_preprocess`. But if `foo.def_eq` is private in a module, then a non-module importing it will still expect a non-private `foo.def_eq` to exist. To patch that, we install a `copyPrivateUnfoldTheorem : GetUnfoldEqnFn` that declares a theorem aliasing the private one. Seems to work.
141 lines
2.7 KiB
Text
141 lines
2.7 KiB
Text
module
|
||
|
||
/-! Module docstring -/
|
||
|
||
/-- A definition. -/
|
||
def f := 1
|
||
|
||
#guard_msgs(drop warning) in
|
||
/-- A theorem. -/
|
||
theorem t : f = 1 := sorry
|
||
|
||
theorem trfl : f = 1 := rfl
|
||
|
||
@[expose] def fexp := 1
|
||
|
||
private def priv := 2
|
||
|
||
/-! Private decls should not be accessible in exported contexts. -/
|
||
|
||
/-- error: unknown identifier 'priv' -/
|
||
#guard_msgs in
|
||
abbrev h := priv
|
||
|
||
|
||
/-! Equational theorems tests. -/
|
||
|
||
def f_struct : Nat → Nat
|
||
| 0 => 0
|
||
| n + 1 => f_struct n
|
||
termination_by structural n => n
|
||
|
||
def f_wfrec : Nat → Nat → Nat
|
||
| 0, acc => acc
|
||
| n + 1, acc => f_wfrec n (acc + 1)
|
||
termination_by n => n
|
||
|
||
@[expose] def f_exp_wfrec : Nat → Nat → Nat
|
||
| 0, acc => acc
|
||
| n + 1, acc => f_exp_wfrec n (acc + 1)
|
||
termination_by n => n
|
||
|
||
@[inline] protected def Test.Option.map (f : α → β) : Option α → Option β
|
||
| some x => some (f x)
|
||
| none => none
|
||
|
||
|
||
/-- error: 'f.eq_def' is a reserved name -/
|
||
#guard_msgs in
|
||
def f.eq_def := 1
|
||
|
||
/-- error: 'fexp.eq_def' is a reserved name -/
|
||
#guard_msgs in
|
||
def fexp.eq_def := 1
|
||
|
||
/-- info: f.eq_def : f = 1 -/
|
||
#guard_msgs in
|
||
#check f.eq_def
|
||
|
||
/-- info: f.eq_unfold : f = 1 -/
|
||
#guard_msgs in
|
||
#check f.eq_unfold
|
||
|
||
/-- info: fexp.eq_def : fexp = 1 -/
|
||
#guard_msgs in
|
||
#check fexp.eq_def
|
||
|
||
/-- info: fexp.eq_unfold : fexp = 1 -/
|
||
#guard_msgs in
|
||
#check fexp.eq_unfold
|
||
|
||
/-- info: f_struct.eq_1 : f_struct 0 = 0 -/
|
||
#guard_msgs in
|
||
#check f_struct.eq_1
|
||
|
||
/--
|
||
info: f_struct.eq_def (x✝ : Nat) :
|
||
f_struct x✝ =
|
||
match x✝ with
|
||
| 0 => 0
|
||
| n.succ => f_struct n
|
||
-/
|
||
#guard_msgs in
|
||
#check f_struct.eq_def
|
||
|
||
/--
|
||
info: f_struct.eq_unfold :
|
||
f_struct = fun x =>
|
||
match x with
|
||
| 0 => 0
|
||
| n.succ => f_struct n
|
||
-/
|
||
#guard_msgs(pass trace, all) in
|
||
#check f_struct.eq_unfold
|
||
|
||
/-- info: f_wfrec.eq_1 (x✝ : Nat) : f_wfrec 0 x✝ = x✝ -/
|
||
#guard_msgs(pass trace, all) in
|
||
#check f_wfrec.eq_1
|
||
|
||
/--
|
||
info: f_wfrec.eq_def (x✝ x✝¹ : Nat) :
|
||
f_wfrec x✝ x✝¹ =
|
||
match x✝, x✝¹ with
|
||
| 0, acc => acc
|
||
| n.succ, acc => f_wfrec n (acc + 1)
|
||
-/
|
||
#guard_msgs in
|
||
#check f_wfrec.eq_def
|
||
|
||
/--
|
||
info: f_wfrec.eq_unfold :
|
||
f_wfrec = fun x x_1 =>
|
||
match x, x_1 with
|
||
| 0, acc => acc
|
||
| n.succ, acc => f_wfrec n (acc + 1)
|
||
-/
|
||
#guard_msgs in
|
||
#check f_wfrec.eq_unfold
|
||
|
||
/-- info: f_exp_wfrec.eq_1 (x✝ : Nat) : f_exp_wfrec 0 x✝ = x✝ -/
|
||
#guard_msgs in
|
||
#check f_exp_wfrec.eq_1
|
||
|
||
/--
|
||
info: f_exp_wfrec.eq_def (x✝ x✝¹ : Nat) :
|
||
f_exp_wfrec x✝ x✝¹ =
|
||
match x✝, x✝¹ with
|
||
| 0, acc => acc
|
||
| n.succ, acc => f_exp_wfrec n (acc + 1)
|
||
-/
|
||
#guard_msgs in
|
||
#check f_exp_wfrec.eq_def
|
||
|
||
/--
|
||
info: f_exp_wfrec.eq_unfold :
|
||
f_exp_wfrec = fun x x_1 =>
|
||
match x, x_1 with
|
||
| 0, acc => acc
|
||
| n.succ, acc => f_exp_wfrec n (acc + 1)
|
||
-/
|
||
#guard_msgs in
|
||
#check f_exp_wfrec.eq_unfold
|