feat(frontends/lean): allow variables anywhere
This commit is contained in:
parent
4010767c20
commit
0641ee33ce
7 changed files with 46 additions and 32 deletions
|
@ -86,7 +86,7 @@ static void check_parameter_type(parser & p, name const & n, expr const & type,
|
||||||
for_each(type, [&](expr const & e, unsigned) {
|
for_each(type, [&](expr const & e, unsigned) {
|
||||||
if (is_local(e) && p.is_section_variable(e))
|
if (is_local(e) && p.is_section_variable(e))
|
||||||
throw parser_error(sstream() << "invalid parameter declaration '" << n << "', it depends on " <<
|
throw parser_error(sstream() << "invalid parameter declaration '" << n << "', it depends on " <<
|
||||||
"section variable '" << local_pp_name(e) << "'", pos);
|
"variable '" << local_pp_name(e) << "'", pos);
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -96,12 +96,14 @@ static environment declare_var(parser & p, environment env,
|
||||||
variable_kind k, optional<binder_info> const & _bi, pos_info const & pos) {
|
variable_kind k, optional<binder_info> const & _bi, pos_info const & pos) {
|
||||||
binder_info bi;
|
binder_info bi;
|
||||||
if (_bi) bi = *_bi;
|
if (_bi) bi = *_bi;
|
||||||
if (in_section_or_context(p.env())) {
|
if (k == variable_kind::Parameter || k == variable_kind::Variable) {
|
||||||
lean_assert(k == variable_kind::Parameter || k == variable_kind::Variable);
|
if (k == variable_kind::Parameter) {
|
||||||
if (k == variable_kind::Parameter)
|
check_in_section_or_context(p);
|
||||||
check_parameter_type(p, n, type, pos);
|
check_parameter_type(p, n, type, pos);
|
||||||
|
}
|
||||||
if (p.get_local(n))
|
if (p.get_local(n))
|
||||||
throw parser_error(sstream() << "invalid declaration, section/context already contains '" << n << "'", pos);
|
throw parser_error(sstream() << "invalid parameter/variable declaration, '"
|
||||||
|
<< n << "' has already been declared", pos);
|
||||||
name u = p.mk_fresh_name();
|
name u = p.mk_fresh_name();
|
||||||
expr l = p.save_pos(mk_local(u, n, type, bi), pos);
|
expr l = p.save_pos(mk_local(u, n, type, bi), pos);
|
||||||
p.add_local_expr(n, l, k == variable_kind::Variable);
|
p.add_local_expr(n, l, k == variable_kind::Variable);
|
||||||
|
@ -124,17 +126,15 @@ static environment declare_var(parser & p, environment env,
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief If we are in a section, then add the new local levels to it. */
|
/** \brief If we are in a section, then add the new local levels to it. */
|
||||||
static void update_section_local_levels(parser & p, level_param_names const & new_ls, bool is_variable) {
|
static void update_local_levels(parser & p, level_param_names const & new_ls, bool is_variable) {
|
||||||
if (in_section_or_context(p.env())) {
|
for (auto const & l : new_ls)
|
||||||
for (auto const & l : new_ls)
|
p.add_local_level(l, mk_param_univ(l), is_variable);
|
||||||
p.add_local_level(l, mk_param_univ(l), is_variable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<binder_info> parse_binder_info(parser & p) {
|
optional<binder_info> parse_binder_info(parser & p, variable_kind k) {
|
||||||
optional<binder_info> bi = p.parse_optional_binder_info();
|
optional<binder_info> bi = p.parse_optional_binder_info();
|
||||||
if (bi)
|
if (bi && k != variable_kind::Parameter && k != variable_kind::Variable)
|
||||||
check_in_section_or_context(p);
|
parser_error("invalid binder annotation, it can only be used to declare variables/parameters", p.pos());
|
||||||
return bi;
|
return bi;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,8 +144,8 @@ static void check_variable_kind(parser & p, variable_kind k) {
|
||||||
throw parser_error("invalid declaration, 'constant/axiom' cannot be used in sections/contexts",
|
throw parser_error("invalid declaration, 'constant/axiom' cannot be used in sections/contexts",
|
||||||
p.pos());
|
p.pos());
|
||||||
} else {
|
} else {
|
||||||
if (k == variable_kind::Parameter || k == variable_kind::Variable)
|
if (k == variable_kind::Parameter)
|
||||||
throw parser_error("invalid declaration, 'parameter/variable/hypothesis/conjecture' "
|
throw parser_error("invalid declaration, 'parameter/hypothesis/conjecture' "
|
||||||
"can only be used in sections/contexts", p.pos());
|
"can only be used in sections/contexts", p.pos());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,13 +153,13 @@ static void check_variable_kind(parser & p, variable_kind k) {
|
||||||
environment variable_cmd_core(parser & p, variable_kind k) {
|
environment variable_cmd_core(parser & p, variable_kind k) {
|
||||||
check_variable_kind(p, k);
|
check_variable_kind(p, k);
|
||||||
auto pos = p.pos();
|
auto pos = p.pos();
|
||||||
optional<binder_info> bi = parse_binder_info(p);
|
optional<binder_info> bi = parse_binder_info(p, k);
|
||||||
name n = p.check_id_next("invalid declaration, identifier expected");
|
name n = p.check_id_next("invalid declaration, identifier expected");
|
||||||
buffer<name> ls_buffer;
|
buffer<name> ls_buffer;
|
||||||
if (p.curr_is_token(get_llevel_curly_tk()) && in_section_or_context(p.env()))
|
if (p.curr_is_token(get_llevel_curly_tk()) && (k == variable_kind::Parameter || k == variable_kind::Variable))
|
||||||
throw parser_error("invalid declaration, axioms/parameters occurring in sections cannot be universe polymorphic", p.pos());
|
throw parser_error("invalid declaration, only constants/axioms can be universe polymorphic", p.pos());
|
||||||
optional<parser::local_scope> scope1;
|
optional<parser::local_scope> scope1;
|
||||||
if (!in_section_or_context(p.env()))
|
if (k == variable_kind::Constant || k == variable_kind::Axiom)
|
||||||
scope1.emplace(p);
|
scope1.emplace(p);
|
||||||
parse_univ_params(p, ls_buffer);
|
parse_univ_params(p, ls_buffer);
|
||||||
expr type;
|
expr type;
|
||||||
|
@ -175,7 +175,7 @@ environment variable_cmd_core(parser & p, variable_kind k) {
|
||||||
}
|
}
|
||||||
p.parse_close_binder_info(bi);
|
p.parse_close_binder_info(bi);
|
||||||
level_param_names ls;
|
level_param_names ls;
|
||||||
if (in_section_or_context(p.env())) {
|
if (ls_buffer.empty()) {
|
||||||
ls = to_level_param_names(collect_univ_params(type));
|
ls = to_level_param_names(collect_univ_params(type));
|
||||||
} else {
|
} else {
|
||||||
update_univ_parameters(ls_buffer, collect_univ_params(type), p);
|
update_univ_parameters(ls_buffer, collect_univ_params(type), p);
|
||||||
|
@ -184,7 +184,8 @@ environment variable_cmd_core(parser & p, variable_kind k) {
|
||||||
level_param_names new_ls;
|
level_param_names new_ls;
|
||||||
list<expr> ctx = p.locals_to_context();
|
list<expr> ctx = p.locals_to_context();
|
||||||
std::tie(type, new_ls) = p.elaborate_type(type, ctx);
|
std::tie(type, new_ls) = p.elaborate_type(type, ctx);
|
||||||
update_section_local_levels(p, new_ls, k == variable_kind::Variable);
|
if (k == variable_kind::Variable || k == variable_kind::Parameter)
|
||||||
|
update_local_levels(p, new_ls, k == variable_kind::Variable);
|
||||||
return declare_var(p, p.env(), n, append(ls, new_ls), type, k, bi, pos);
|
return declare_var(p, p.env(), n, append(ls, new_ls), type, k, bi, pos);
|
||||||
}
|
}
|
||||||
environment variable_cmd(parser & p) {
|
environment variable_cmd(parser & p) {
|
||||||
|
@ -205,7 +206,7 @@ static environment variables_cmd_core(parser & p, variable_kind k) {
|
||||||
auto pos = p.pos();
|
auto pos = p.pos();
|
||||||
environment env = p.env();
|
environment env = p.env();
|
||||||
while (true) {
|
while (true) {
|
||||||
optional<binder_info> bi = parse_binder_info(p);
|
optional<binder_info> bi = parse_binder_info(p, k);
|
||||||
buffer<name> ids;
|
buffer<name> ids;
|
||||||
while (!p.curr_is_token(get_colon_tk())) {
|
while (!p.curr_is_token(get_colon_tk())) {
|
||||||
name id = p.check_id_next("invalid parameters declaration, identifier expected");
|
name id = p.check_id_next("invalid parameters declaration, identifier expected");
|
||||||
|
@ -213,7 +214,7 @@ static environment variables_cmd_core(parser & p, variable_kind k) {
|
||||||
}
|
}
|
||||||
p.next();
|
p.next();
|
||||||
optional<parser::local_scope> scope1;
|
optional<parser::local_scope> scope1;
|
||||||
if (!in_section_or_context(p.env()))
|
if (k == variable_kind::Constant || k == variable_kind::Axiom)
|
||||||
scope1.emplace(p);
|
scope1.emplace(p);
|
||||||
expr type = p.parse_expr();
|
expr type = p.parse_expr();
|
||||||
p.parse_close_binder_info(bi);
|
p.parse_close_binder_info(bi);
|
||||||
|
@ -225,7 +226,8 @@ static environment variables_cmd_core(parser & p, variable_kind k) {
|
||||||
level_param_names new_ls;
|
level_param_names new_ls;
|
||||||
expr new_type;
|
expr new_type;
|
||||||
std::tie(new_type, new_ls) = p.elaborate_type(type, ctx);
|
std::tie(new_type, new_ls) = p.elaborate_type(type, ctx);
|
||||||
update_section_local_levels(p, new_ls, k == variable_kind::Variable);
|
if (k == variable_kind::Variable || k == variable_kind::Parameter)
|
||||||
|
update_local_levels(p, new_ls, k == variable_kind::Variable);
|
||||||
new_ls = append(ls, new_ls);
|
new_ls = append(ls, new_ls);
|
||||||
env = declare_var(p, env, id, new_ls, new_type, k, bi, pos);
|
env = declare_var(p, env, id, new_ls, new_type, k, bi, pos);
|
||||||
}
|
}
|
||||||
|
@ -245,7 +247,6 @@ static environment constants_cmd(parser & p) {
|
||||||
return variables_cmd_core(p, variable_kind::Constant);
|
return variables_cmd_core(p, variable_kind::Constant);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct decl_modifiers {
|
struct decl_modifiers {
|
||||||
bool m_is_instance;
|
bool m_is_instance;
|
||||||
bool m_is_coercion;
|
bool m_is_coercion;
|
||||||
|
@ -365,7 +366,7 @@ environment definition_cmd_core(parser & p, bool is_theorem, bool is_opaque, boo
|
||||||
real_n = ns + n;
|
real_n = ns + n;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_section_or_context(env)) {
|
if (p.has_locals()) {
|
||||||
buffer<expr> section_ps;
|
buffer<expr> section_ps;
|
||||||
collect_section_locals(type, value, p, section_ps);
|
collect_section_locals(type, value, p, section_ps);
|
||||||
type = Pi_as_is(section_ps, type, p);
|
type = Pi_as_is(section_ps, type, p);
|
||||||
|
@ -515,7 +516,7 @@ environment include_cmd_core(parser & p, bool include) {
|
||||||
name n = p.get_name_val();
|
name n = p.get_name_val();
|
||||||
p.next();
|
p.next();
|
||||||
if (!p.get_local(n))
|
if (!p.get_local(n))
|
||||||
throw parser_error(sstream() << "invalid include/omit command, '" << n << "' is not a section parameter/variable", pos);
|
throw parser_error(sstream() << "invalid include/omit command, '" << n << "' is not a parameter/variable", pos);
|
||||||
if (include) {
|
if (include) {
|
||||||
if (p.is_include_variable(n))
|
if (p.is_include_variable(n))
|
||||||
throw parser_error(sstream() << "invalid include command, '" << n << "' has already been included", pos);
|
throw parser_error(sstream() << "invalid include command, '" << n << "' has already been included", pos);
|
||||||
|
|
|
@ -387,7 +387,7 @@ struct inductive_cmd_fn {
|
||||||
|
|
||||||
/** \brief Include in m_levels any section level referenced by decls. */
|
/** \brief Include in m_levels any section level referenced by decls. */
|
||||||
void include_section_levels(buffer<inductive_decl> const & decls) {
|
void include_section_levels(buffer<inductive_decl> const & decls) {
|
||||||
if (!in_section_or_context(m_env))
|
if (!m_p.has_locals())
|
||||||
return;
|
return;
|
||||||
name_set all_lvl_params;
|
name_set all_lvl_params;
|
||||||
for (auto const & d : decls) {
|
for (auto const & d : decls) {
|
||||||
|
@ -448,7 +448,7 @@ struct inductive_cmd_fn {
|
||||||
The section parameters are stored in section_params
|
The section parameters are stored in section_params
|
||||||
*/
|
*/
|
||||||
void abstract_section_locals(buffer<inductive_decl> & decls, buffer<expr> & section_params) {
|
void abstract_section_locals(buffer<inductive_decl> & decls, buffer<expr> & section_params) {
|
||||||
if (!in_section_or_context(m_env))
|
if (!m_p.has_locals())
|
||||||
return;
|
return;
|
||||||
expr_struct_set section_locals;
|
expr_struct_set section_locals;
|
||||||
collect_section_locals(decls, section_locals);
|
collect_section_locals(decls, section_locals);
|
||||||
|
@ -593,7 +593,7 @@ struct inductive_cmd_fn {
|
||||||
id = name(name(full_id.get_prefix().get_string()), full_id.get_string());
|
id = name(name(full_id.get_prefix().get_string()), full_id.get_string());
|
||||||
else
|
else
|
||||||
id = name(full_id.get_string());
|
id = name(full_id.get_string());
|
||||||
if (in_section_or_context(env)) {
|
if (!empty(section_levels) || !section_params.empty()) {
|
||||||
expr r = mk_section_local_ref(full_id, section_levels, section_params);
|
expr r = mk_section_local_ref(full_id, section_levels, section_params);
|
||||||
m_p.add_local_expr(id, r);
|
m_p.add_local_expr(id, r);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ public:
|
||||||
std::tie(m_map, m_counter, m_entries) = head(m_scopes);
|
std::tie(m_map, m_counter, m_entries) = head(m_scopes);
|
||||||
m_scopes = tail(m_scopes);
|
m_scopes = tail(m_scopes);
|
||||||
}
|
}
|
||||||
|
bool empty() const { return m_map.empty(); }
|
||||||
struct mk_scope {
|
struct mk_scope {
|
||||||
local_decls & m_d;
|
local_decls & m_d;
|
||||||
mk_scope(local_decls & d):m_d(d) { m_d.push(); }
|
mk_scope(local_decls & d):m_d(d) { m_d.push(); }
|
||||||
|
|
|
@ -331,6 +331,7 @@ public:
|
||||||
expr parse_scoped_expr(buffer<expr> & ps, unsigned rbp = 0) { return parse_scoped_expr(ps.size(), ps.data(), rbp); }
|
expr parse_scoped_expr(buffer<expr> & ps, unsigned rbp = 0) { return parse_scoped_expr(ps.size(), ps.data(), rbp); }
|
||||||
|
|
||||||
struct local_scope { parser & m_p; environment m_env; local_scope(parser & p); ~local_scope(); };
|
struct local_scope { parser & m_p; environment m_env; local_scope(parser & p); ~local_scope(); };
|
||||||
|
bool has_locals() const { return !m_local_decls.empty() || !m_local_level_decls.empty(); }
|
||||||
void add_local_level(name const & n, level const & l, bool is_variable = false);
|
void add_local_level(name const & n, level const & l, bool is_variable = false);
|
||||||
void add_local_expr(name const & n, expr const & p, bool is_variable = false);
|
void add_local_expr(name const & n, expr const & p, bool is_variable = false);
|
||||||
void add_local(expr const & p) { return add_local_expr(local_pp_name(p), p); }
|
void add_local(expr const & p) { return add_local_expr(local_pp_name(p), p); }
|
||||||
|
|
11
tests/lean/run/vars_anywhere.lean
Normal file
11
tests/lean/run/vars_anywhere.lean
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
variable {A : Type}
|
||||||
|
|
||||||
|
definition id (a : A) := a
|
||||||
|
|
||||||
|
check @id
|
||||||
|
|
||||||
|
inductive list :=
|
||||||
|
nil : list,
|
||||||
|
cons : A → list → list
|
||||||
|
|
||||||
|
check @list.cons
|
|
@ -1 +1 @@
|
||||||
sec.lean:7:11: error: invalid declaration, section/context already contains 'A'
|
sec.lean:7:11: error: invalid parameter/variable declaration, 'A' has already been declared
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
var.lean:6:12: error: invalid parameter declaration 'a', it depends on section variable 'A'
|
var.lean:6:12: error: invalid parameter declaration 'a', it depends on variable 'A'
|
||||||
|
|
Loading…
Reference in a new issue