diff --git a/src/frontends/lean/builtin_cmds.cpp b/src/frontends/lean/builtin_cmds.cpp index 385e8c180..7e7f2440a 100644 --- a/src/frontends/lean/builtin_cmds.cpp +++ b/src/frontends/lean/builtin_cmds.cpp @@ -445,6 +445,24 @@ static name parse_metaclass(parser & p) { } } +static void parse_metaclasses(parser & p, buffer & r) { + if (p.curr_is_token(get_sub_tk())) { + p.next(); + buffer tmp; + get_metaclasses(tmp); + tmp.push_back(get_decls_tk()); + while (p.curr_is_token(get_lbracket_tk())) { + name m = parse_metaclass(p); + tmp.erase_elem(m); + } + r.append(tmp); + } else { + while (p.curr_is_token(get_lbracket_tk())) { + r.push_back(parse_metaclass(p)); + } + } +} + static void check_identifier(parser & p, environment const & env, name const & ns, name const & id) { name full_id = ns + id; if (!env.find(full_id)) @@ -473,8 +491,13 @@ static environment add_abbrev(parser & p, environment const & env, name const & environment open_export_cmd(parser & p, bool open) { environment env = p.env(); while (true) { - name cls = parse_metaclass(p); - bool decls = cls.is_anonymous() || cls == get_decls_tk() || cls == get_declarations_tk(); + buffer metacls; + parse_metaclasses(p, metacls); + bool decls = false; + if (metacls.empty() || + std::find(metacls.begin(), metacls.end(), get_decls_tk()) != metacls.end() || + std::find(metacls.begin(), metacls.end(), get_declarations_tk()) != metacls.end()) + decls = true; auto pos = p.pos(); name ns = p.check_id_next("invalid 'open/export' command, identifier expected"); optional real_ns = to_valid_namespace_name(env, ns); @@ -487,9 +510,9 @@ environment open_export_cmd(parser & p, bool open) { as = p.check_id_next("invalid 'open/export' command, identifier expected"); } if (open) - env = using_namespace(env, p.ios(), ns, cls); + env = using_namespace(env, p.ios(), ns, metacls); else - env = export_namespace(env, p.ios(), ns, cls); + env = export_namespace(env, p.ios(), ns, metacls); if (decls) { // Remark: we currently to not allow renaming and hiding of universe levels buffer exceptions; diff --git a/src/library/scoped_ext.cpp b/src/library/scoped_ext.cpp index 3c7f9ef11..9d23271dd 100644 --- a/src/library/scoped_ext.cpp +++ b/src/library/scoped_ext.cpp @@ -80,24 +80,43 @@ bool is_metaclass(name const & n) { return false; } -environment using_namespace(environment const & env, io_state const & ios, name const & n, name const & c) { +environment using_namespace(environment const & env, io_state const & ios, name const & n, buffer const & metaclasses) { environment r = env; for (auto const & t : get_exts()) { - if (c.is_anonymous() || c == std::get<0>(t)) + if (metaclasses.empty() || + std::find(metaclasses.begin(), metaclasses.end(), std::get<0>(t)) != metaclasses.end()) r = std::get<1>(t)(r, ios, n); } return r; } -environment export_namespace(environment const & env, io_state const & ios, name const & n, name const & c) { +static environment using_namespace(environment const & env, io_state const & ios, name const & n, name const & metaclass) { + buffer tmp; + if (!metaclass.is_anonymous()) + tmp.push_back(metaclass); + return using_namespace(env, ios, n, tmp); +} + +environment using_namespace(environment const & env, io_state const & ios, name const & n) { + buffer metaclasses; + return using_namespace(env, ios, n, metaclasses); +} + +environment export_namespace(environment const & env, io_state const & ios, name const & n, buffer const & metaclasses) { environment r = env; for (auto const & t : get_exts()) { - if (c.is_anonymous() || c == std::get<0>(t)) + if (metaclasses.empty() || + std::find(metaclasses.begin(), metaclasses.end(), std::get<0>(t)) != metaclasses.end()) r = std::get<2>(t)(r, ios, n); } return r; } +environment export_namespace(environment const & env, io_state const & ios, name const & n) { + buffer metaclasses; + return export_namespace(env, ios, n, metaclasses); +} + optional to_valid_namespace_name(environment const & env, name const & n) { scope_mng_ext const & ext = get_extension(env); if (ext.m_namespace_set.contains(n)) diff --git a/src/library/scoped_ext.h b/src/library/scoped_ext.h index 09c75ae2d..7efa3f8f5 100644 --- a/src/library/scoped_ext.h +++ b/src/library/scoped_ext.h @@ -23,11 +23,14 @@ typedef environment (*push_scope_fn)(environment const &, scope_kind); typedef environment (*pop_scope_fn)(environment const &, scope_kind); void register_scoped_ext(name const & n, using_namespace_fn use, export_namespace_fn ex, push_scope_fn push, pop_scope_fn pop); -/** \brief Use objects defined in the namespace \c n. If \c c is not the anonymous name, then only objects from "class" \c c are considered. */ -environment using_namespace(environment const & env, io_state const & ios, name const & n, name const & c = name()); +/** \brief Use objects defined in the namespace \c n. + If \c metaclasses is not empty, then only objects in the given "metaclasses" \c c are considered. */ +environment using_namespace(environment const & env, io_state const & ios, name const & n, buffer const & metaclasses); +environment using_namespace(environment const & env, io_state const & ios, name const & n); /** \brief Export objects defined in the namespace \c n to current namespace. - If \c c is not the anonymous name, then only objects from "class" \c c are considered. */ -environment export_namespace(environment const & env, io_state const & ios, name const & n, name const & c = name()); + If \c metaclasses is not empty, then only objects in the given "metaclasses" \c c are considered. */ +environment export_namespace(environment const & env, io_state const & ios, name const & n, buffer const & metaclasses); +environment export_namespace(environment const & env, io_state const & ios, name const & n); /** \brief Create a new scope, all scoped extensions are notified. */ environment push_scope(environment const & env, io_state const & ios, scope_kind k, name const & n = name()); diff --git a/tests/lean/open_tst.lean b/tests/lean/open_tst.lean new file mode 100644 index 000000000..bcf4f8ab6 --- /dev/null +++ b/tests/lean/open_tst.lean @@ -0,0 +1,42 @@ +context + open [notations] [coercions] nat + check 1 + 2 + check add -- Error aliases were not created +end + +context + open [declarations] [notations] nat + variable a : nat + check a + a + check add a a + check a + 1 -- Error coercion from num to nat was not loaded +end + +context + open - [classes] nat + variable a : nat + check a + a + check add a a + check a + 1 + definition foo1 : inhabited nat := + _ -- Error inhabited instances was not loaded +end + +context + open - [classes] [decls] nat + variable a : nat + check a + a + check add a a -- Error aliases were not created + check a + 1 + definition foo2 : inhabited nat := + _ -- Error inhabited instances was not loaded +end + +context + open [classes] nat + definition foo3 : inhabited nat := + _ + + variable a : nat + check a + a -- Error notation declarations were not loaded +end diff --git a/tests/lean/open_tst.lean.expected.out b/tests/lean/open_tst.lean.expected.out new file mode 100644 index 000000000..9e9beb5c6 --- /dev/null +++ b/tests/lean/open_tst.lean.expected.out @@ -0,0 +1,29 @@ +1 + 2 : ℕ +open_tst.lean:4:8: error: unknown identifier 'add' +a + a : ℕ +a + a : ℕ +open_tst.lean:12:10: error: type mismatch at application + a + 1 +term + 1 +has type + num +but is expected to have type + ℕ +a + a : ℕ +a + a : ℕ +a + 1 : ℕ +open_tst.lean:22:2: error: don't know how to synthesize placeholder + +⊢ inhabited ℕ +open_tst.lean:22:2: error: failed to add declaration 'foo1' to environment, value has metavariables + ?M_1 +a + a : ℕ +open_tst.lean:29:8: error: unknown identifier 'add' +a + 1 : ℕ +open_tst.lean:32:2: error: don't know how to synthesize placeholder + +⊢ inhabited ℕ +open_tst.lean:32:2: error: failed to add declaration 'foo2' to environment, value has metavariables + ?M_1 +open_tst.lean:41:10: error: invalid expression