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

Commit e6fda2a

Browse files
committed
fix(transform_decl): fix namespace bug (#8733)
* The problem was that when writing `@[to_additive] def foo ...` every declaration used in `foo` in namespace `foo` would be additivized without changing the last part of the name. This behavior was intended to translate automatically generated declarations like `foo._proof_1`. However, if `foo` contains a non-internal declaration `foo.bar` and `add_foo.bar` didn't exist yet, it would also create a declaration `add_foo.bar` additivizing `foo.bar`. * This PR changes the behavior: if `foo.bar` has the `@[to_additive]` attribute (potentially with a custom additive name), then we won't create a second additive version of `foo.bar`, and succeed normally. However, if `foo.bar` doesn't have the `@[to_additive]` attribute, then we fail with a nice error message. We could potentially support this behavior, but it doesn't seem that worthwhile and it would require changing a couple low-level definitions that `@[to_additive]` uses (e.g. by replacing `name.map_prefix` so that it only maps prefixes if the name is `internal`). * So far this didn't happen in the library yet. There are currently 5 non-internal declarations `foo.bar` that are used in `foo` where `foo` has the `@[to_additive]` attribute, but all of these declarations were already had an additive version `add_foo.bar`. * These 5 declarations are `[Mon.has_limits.limit_cone, Mon.has_limits.limit_cone_is_limit, con_gen.rel, magma.free_semigroup.r, localization.r]` * This fixes the error in #8707 and resolves the Zulip thread https://leanprover.zulipchat.com/#narrow/stream/144837-PR-reviews/topic/.238707.20linter.20weirdness * I also added some documentation / comments to the function `transform_decl_with_prefix_fun_aux`, made it non-private, and rewrote some steps.
1 parent 9a249ee commit e6fda2a

File tree

2 files changed

+48
-16
lines changed

2 files changed

+48
-16
lines changed

src/tactic/transform_decl.lean

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,30 +44,43 @@ meta def additive_test (f : name → option name) (replace_all : bool) (ignore :
4444
(e : expr) : bool :=
4545
if replace_all then tt else additive_test_aux f ignore ff e
4646

47-
private meta def transform_decl_with_prefix_fun_aux (f : name → option name)
47+
/-- transform the declaration `src` and all declarations `pre._proof_i` occurring in `src`
48+
using the dictionary `f`.
49+
`replace_all`, `trace`, `ignore` and `reorder` are configuration options.
50+
`pre` is the declaration that got the `@[to_additive]` attribute and `tgt_pre` is the target of this
51+
declaration. -/
52+
meta def transform_decl_with_prefix_fun_aux (f : name → option name)
4853
(replace_all trace : bool) (ignore reorder : name_map $ list ℕ) (pre tgt_pre : name)
4954
(attrs : list name) : name → command :=
5055
λ src,
5156
do
57+
-- if this declaration is not `pre` or an internal declaration, we do nothing.
58+
tt ← return (src = pre ∨ src.is_internal : bool) |
59+
if (f src).is_some then skip else fail!("@[to_additive] failed.
60+
The declaration {pre} depends on the declaration {src} which is in the namespace {pre}, but " ++
61+
"does not have the `@[to_additive]` attribute. This is not supported. Workaround: move {src} to " ++
62+
"a different namespace."),
63+
env ← get_env,
64+
-- we find the additive name of `src`
5265
let tgt := src.map_prefix (λ n, if n = pre then some tgt_pre else none),
53-
(get_decl tgt >> skip) <|>
54-
do
55-
decl ← get_decl src,
56-
(decl.type.list_names_with_prefix pre).mfold () (λ n _, transform_decl_with_prefix_fun_aux n),
57-
(decl.value.list_names_with_prefix pre).mfold () (λ n _, transform_decl_with_prefix_fun_aux n),
58-
is_protected ← is_protected_decl src,
59-
env ← get_env,
60-
let decl :=
61-
decl.update_with_fun env (name.map_prefix f) (additive_test f replace_all ignore) reorder tgt,
62-
pp_decl ← pp decl,
63-
when trace $ trace!"[to_additive] > generating\n{pp_decl}",
64-
decorate_error (format!"@[to_additive] failed. Type mismatch in additive declaration.
66+
-- we skip if we already transformed this declaration before
67+
ff ← return $ env.contains tgt | skip,
68+
decl ← get_decl src,
69+
-- we first transform all the declarations of the form `pre._proof_i`
70+
(decl.type.list_names_with_prefix pre).mfold () (λ n _, transform_decl_with_prefix_fun_aux n),
71+
(decl.value.list_names_with_prefix pre).mfold () (λ n _, transform_decl_with_prefix_fun_aux n),
72+
-- we transform `decl` using `f` and the configuration options.
73+
let decl :=
74+
decl.update_with_fun env (name.map_prefix f) (additive_test f replace_all ignore) reorder tgt,
75+
pp_decl ← pp decl,
76+
when trace $ trace!"[to_additive] > generating\n{pp_decl}",
77+
decorate_error (format!"@[to_additive] failed. Type mismatch in additive declaration.
6578
For help, see the docstring of `to_additive.attr`, section `Troubleshooting`.
6679
Failed to add declaration\n{pp_decl}
6780
68-
Nested error message:\n").to_string $ -- empty line is intentional
69-
if is_protected then add_protected_decl decl else add_decl decl,
70-
attrs.mmap' (λ n, copy_attribute n src tgt)
81+
Nested error message:\n").to_string $ -- the empty line is intentional
82+
if env.is_protected src then add_protected_decl decl else add_decl decl,
83+
attrs.mmap' $ λ n, copy_attribute n src tgt
7184

7285
/--
7386
Make a new copy of a declaration,

test/to_additive.lean

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,22 @@ let t := d.type.eta_expand env reorder,
5858
let decl := declaration.defn `barr6 d.univ_params t e d.reducibility_hints d.is_trusted,
5959
add_decl decl,
6060
skip
61+
62+
/-! Test the namespace bug (#8733). This code should *not* generate a lemma
63+
`add_some_def.in_namespace`. -/
64+
def some_def.in_namespace : bool := ff
65+
66+
def some_def {α : Type*} [has_mul α] (x : α) : α :=
67+
if some_def.in_namespace then x * x else x
68+
69+
-- cannot apply `@[to_additive]` to `some_def` if `some_def.in_namespace` doesn't have the attribute
70+
run_cmd do
71+
dict ← to_additive.aux_attr.get_cache,
72+
success_if_fail
73+
(transform_decl_with_prefix_dict dict ff tt mk_name_map mk_name_map `some_def `add_some_def []),
74+
skip
75+
76+
attribute [to_additive some_other_name] some_def.in_namespace
77+
attribute [to_additive add_some_def] some_def
78+
79+
run_cmd success_if_fail (get_decl `add_some_def.in_namespace)

0 commit comments

Comments
 (0)