feat(frontends/lean): allow parameters to be used in sections
Restriction: - coercions and notations cannot be defined in parametric sections closes #401
This commit is contained in:
parent
b643063955
commit
b5c4e603db
9 changed files with 73 additions and 12 deletions
|
@ -537,8 +537,9 @@ environment open_cmd(parser & p) { return open_export_cmd(p, true); }
|
|||
environment export_cmd(parser & p) { return open_export_cmd(p, false); }
|
||||
|
||||
environment coercion_cmd(parser & p) {
|
||||
if (in_context(p.env()))
|
||||
throw parser_error("invalid 'coercion' command, coercions cannot be defined in contexts", p.pos());
|
||||
if (in_context_or_parametric_section(p))
|
||||
throw parser_error("invalid 'coercion' command, coercions cannot be defined in contexts or "
|
||||
"sections containing parameters", p.pos());
|
||||
bool persistent = false;
|
||||
parse_persistent(p, persistent);
|
||||
name f = p.check_constant_next("invalid 'coercion' command, constant expected");
|
||||
|
|
|
@ -116,7 +116,7 @@ static environment declare_var(parser & p, environment env,
|
|||
if (_bi) bi = *_bi;
|
||||
if (k == variable_kind::Parameter || k == variable_kind::Variable) {
|
||||
if (k == variable_kind::Parameter) {
|
||||
check_in_context(p);
|
||||
check_in_context_or_section(p);
|
||||
check_parameter_type(p, n, type, pos);
|
||||
}
|
||||
if (p.get_local(n))
|
||||
|
@ -124,7 +124,10 @@ static environment declare_var(parser & p, environment env,
|
|||
<< n << "' has already been declared", pos);
|
||||
name u = p.mk_fresh_name();
|
||||
expr l = p.save_pos(mk_local(u, n, type, bi), pos);
|
||||
p.add_local_expr(n, l, k == variable_kind::Variable);
|
||||
if (k == variable_kind::Parameter)
|
||||
p.add_parameter(n, l);
|
||||
else
|
||||
p.add_local_expr(n, l, k == variable_kind::Variable);
|
||||
return env;
|
||||
} else {
|
||||
lean_assert(k == variable_kind::Constant || k == variable_kind::Axiom);
|
||||
|
@ -162,10 +165,9 @@ static void check_variable_kind(parser & p, variable_kind k) {
|
|||
if (k == variable_kind::Axiom || k == variable_kind::Constant)
|
||||
throw parser_error("invalid declaration, 'constant/axiom' cannot be used in contexts",
|
||||
p.pos());
|
||||
} else {
|
||||
if (k == variable_kind::Parameter)
|
||||
throw parser_error("invalid declaration, 'parameter/hypothesis/conjecture' "
|
||||
"can only be used in contexts", p.pos());
|
||||
} else if (!in_section(p.env()) && !in_context(p.env()) && k == variable_kind::Parameter) {
|
||||
throw parser_error("invalid declaration, 'parameter/hypothesis/conjecture' "
|
||||
"can only be used in contexts and sections", p.pos());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -629,6 +629,7 @@ struct notation_modifiers {
|
|||
};
|
||||
|
||||
static environment notation_cmd_core(parser & p, bool overload, bool reserve) {
|
||||
check_not_in_parametric_section(p);
|
||||
notation_modifiers mods;
|
||||
mods.parse(p);
|
||||
flet<bool> set_allow_local(g_allow_local, in_context(p.env()) || !mods.m_persistent);
|
||||
|
@ -642,6 +643,7 @@ static environment notation_cmd_core(parser & p, bool overload, bool reserve) {
|
|||
}
|
||||
|
||||
static environment mixfix_cmd(parser & p, mixfix_kind k, bool overload, bool reserve) {
|
||||
check_not_in_parametric_section(p);
|
||||
notation_modifiers mods;
|
||||
mods.parse(p);
|
||||
flet<bool> set_allow_local(g_allow_local, in_context(p.env()) || !mods.m_persistent);
|
||||
|
|
|
@ -104,6 +104,7 @@ parser::parser(environment const & env, io_state const & ios,
|
|||
m_scanner(strm, strm_name, s ? s->m_line : 1),
|
||||
m_theorem_queue(*this, num_threads > 1 ? num_threads - 1 : 0),
|
||||
m_snapshot_vector(sv), m_info_manager(im), m_cache(nullptr), m_index(nullptr) {
|
||||
m_has_params = false;
|
||||
m_keep_theorem_mode = tmode;
|
||||
if (s) {
|
||||
m_local_level_decls = s->m_lds;
|
||||
|
@ -438,7 +439,8 @@ void parser::push_local_scope(bool save_options) {
|
|||
optional<options> opts;
|
||||
if (save_options)
|
||||
opts = m_ios.get_options();
|
||||
m_parser_scope_stack = cons(parser_scope_stack_elem(opts, m_level_variables, m_variables, m_include_vars, m_undef_ids.size()),
|
||||
m_parser_scope_stack = cons(parser_scope_stack_elem(opts, m_level_variables, m_variables, m_include_vars,
|
||||
m_undef_ids.size(), m_has_params),
|
||||
m_parser_scope_stack);
|
||||
}
|
||||
|
||||
|
@ -457,6 +459,7 @@ void parser::pop_local_scope() {
|
|||
m_level_variables = s.m_level_variables;
|
||||
m_variables = s.m_variables;
|
||||
m_include_vars = s.m_include_vars;
|
||||
m_has_params = s.m_has_params;
|
||||
m_undef_ids.shrink(s.m_num_undef_ids);
|
||||
m_parser_scope_stack = tail(m_parser_scope_stack);
|
||||
}
|
||||
|
@ -481,6 +484,12 @@ void parser::add_local_expr(name const & n, expr const & p, bool is_variable) {
|
|||
}
|
||||
}
|
||||
|
||||
void parser::add_parameter(name const & n, expr const & p) {
|
||||
lean_assert(is_local(p));
|
||||
add_local_expr(n, p, false);
|
||||
m_has_params = true;
|
||||
}
|
||||
|
||||
unsigned parser::get_local_level_index(name const & n) const {
|
||||
return m_local_level_decls.find_idx(n);
|
||||
}
|
||||
|
|
|
@ -53,9 +53,11 @@ struct parser_scope_stack_elem {
|
|||
name_set m_variables;
|
||||
name_set m_include_vars;
|
||||
unsigned m_num_undef_ids;
|
||||
bool m_has_params;
|
||||
parser_scope_stack_elem(optional<options> const & o, name_set const & lvs, name_set const & vs, name_set const & ivs,
|
||||
unsigned num_undef_ids):
|
||||
m_options(o), m_level_variables(lvs), m_variables(vs), m_include_vars(ivs), m_num_undef_ids(num_undef_ids) {}
|
||||
unsigned num_undef_ids, bool has_params):
|
||||
m_options(o), m_level_variables(lvs), m_variables(vs), m_include_vars(ivs),
|
||||
m_num_undef_ids(num_undef_ids), m_has_params(has_params) {}
|
||||
};
|
||||
typedef list<parser_scope_stack_elem> parser_scope_stack;
|
||||
|
||||
|
@ -97,6 +99,7 @@ class parser {
|
|||
scanner::token_kind m_curr;
|
||||
local_level_decls m_local_level_decls;
|
||||
local_expr_decls m_local_decls;
|
||||
bool m_has_params; // true context context contains parameters
|
||||
name_set m_level_variables;
|
||||
name_set m_variables; // subset of m_local_decls that is marked as variables
|
||||
name_set m_include_vars; // subset of m_local_decls that is marked as include
|
||||
|
@ -383,7 +386,9 @@ public:
|
|||
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_expr(name const & n, expr const & p, bool is_variable = false);
|
||||
void add_parameter(name const & n, expr const & p);
|
||||
void add_local(expr const & p) { return add_local_expr(local_pp_name(p), p); }
|
||||
bool has_params() const { return m_has_params; }
|
||||
bool is_local_decl(expr const & l) const { return is_local(l) && m_local_decls.contains(local_pp_name(l)); }
|
||||
bool is_local_level_variable(name const & n) const { return m_level_variables.contains(n); }
|
||||
bool is_local_variable(name const & n) const { return m_variables.contains(n); }
|
||||
|
|
|
@ -40,9 +40,29 @@ void check_in_context(parser const & p) {
|
|||
if (!in_context(p.env()))
|
||||
throw exception(sstream() << "invalid command, it must be used in a (local) context");
|
||||
}
|
||||
|
||||
void check_in_context_or_section(parser const & p) {
|
||||
if (!in_context(p.env()) && !in_section(p.env()))
|
||||
throw exception(sstream() << "invalid command, it must be used in a (local) context or section");
|
||||
}
|
||||
|
||||
bool in_parametric_section(parser const & p) {
|
||||
return in_section(p.env()) && p.has_params();
|
||||
}
|
||||
|
||||
void check_not_in_parametric_section(parser const & p) {
|
||||
if (in_parametric_section(p))
|
||||
throw exception(sstream() << "invalid command, it cannot be used in sections containing parameters");
|
||||
}
|
||||
|
||||
bool in_context_or_parametric_section(parser const & p) {
|
||||
return in_context(p.env()) || in_parametric_section(p);
|
||||
}
|
||||
|
||||
bool is_root_namespace(name const & n) {
|
||||
return n == get_root_tk();
|
||||
}
|
||||
|
||||
name remove_root_prefix(name const & n) {
|
||||
return n.replace_prefix(get_root_tk(), name());
|
||||
}
|
||||
|
|
|
@ -21,6 +21,10 @@ bool parse_persistent(parser & p, bool & persistent);
|
|||
|
||||
void check_atomic(name const & n);
|
||||
void check_in_context(parser const & p);
|
||||
void check_in_context_or_section(parser const & p);
|
||||
void check_not_in_parametric_section(parser const & p);
|
||||
bool in_parametric_section(parser const & p);
|
||||
bool in_context_or_parametric_section(parser const & p);
|
||||
bool is_root_namespace(name const & n);
|
||||
name remove_root_prefix(name const & n);
|
||||
/** \brief Return the local levels in \c ls that are not tagged as variables.
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
bad_coercions.lean:12:18: error: invalid '[coercion]' modifier, coercions cannot be defined in contexts
|
||||
bad_coercions.lean:18:11: error: invalid 'coercion' command, coercions cannot be defined in contexts
|
||||
bad_coercions.lean:18:11: error: invalid 'coercion' command, coercions cannot be defined in contexts or sections containing parameters
|
||||
|
|
18
tests/lean/run/section5.lean
Normal file
18
tests/lean/run/section5.lean
Normal file
|
@ -0,0 +1,18 @@
|
|||
section foo
|
||||
parameter A : Type
|
||||
variable a : A
|
||||
definition foo := a
|
||||
|
||||
check foo
|
||||
|
||||
structure point [class] :=
|
||||
(x : A) (y : A)
|
||||
end foo
|
||||
|
||||
check foo
|
||||
|
||||
definition point_nat [instance] : point nat :=
|
||||
point.mk nat.zero nat.zero
|
||||
|
||||
print classes
|
||||
check point
|
Loading…
Reference in a new issue