feat(frontends/lean): automatically include anonymous instance implicit variables/parameters (whenever their parameters have been included)

This commit is contained in:
Leonardo de Moura 2015-12-13 13:20:07 -08:00
parent b6bac2e542
commit 20de22a8ad
7 changed files with 204 additions and 52 deletions

View file

@ -222,15 +222,48 @@ static environment variable_cmd_core(parser & p, variable_kind k, bool is_protec
check_variable_kind(p, k);
auto pos = p.pos();
optional<binder_info> bi = parse_binder_info(p, k);
name n = p.check_decl_id_next("invalid declaration, identifier expected");
optional<parser::local_scope> scope1;
name n;
expr type;
buffer<name> ls_buffer;
if (bi && bi->is_inst_implicit() && (k == variable_kind::Parameter || k == variable_kind::Variable)) {
/* instance implicit */
if (p.curr_is_identifier()) {
auto n_pos = p.pos();
n = p.get_name_val();
p.next();
if (p.curr_is_token(get_colon_tk())) {
/* simple decl: variable [decA : decidable A] */
p.next();
type = p.parse_expr();
} else if (p.curr_is_token(get_rbracket_tk())) {
/* annotation update: variable [decA] */
p.parse_close_binder_info(bi);
update_local_binder_info(p, k, n, bi, pos);
return p.env();
} else {
/* anonymous : variable [decidable A] */
expr left = p.id_to_expr(n, n_pos);
n = p.mk_anonymous_inst_name();
unsigned rbp = 0;
while (rbp < p.curr_expr_lbp()) {
left = p.parse_led(left);
}
type = left;
}
} else {
/* anonymous : variable [forall x y, decidable (x = y)] */
n = p.mk_anonymous_inst_name();
type = p.parse_expr();
}
} else {
/* non instance implicit cases */
n = p.check_decl_id_next("invalid declaration, identifier expected");
if (p.curr_is_token(get_llevel_curly_tk()) && (k == variable_kind::Parameter || k == variable_kind::Variable))
throw parser_error("invalid declaration, only constants/axioms can be universe polymorphic", p.pos());
optional<parser::local_scope> scope1;
if (k == variable_kind::Constant || k == variable_kind::Axiom)
scope1.emplace(p);
parse_univ_params(p, ls_buffer);
expr type;
if (!p.curr_is_token(get_colon_tk())) {
if (!curr_is_binder_annotation(p) && (k == variable_kind::Parameter || k == variable_kind::Variable)) {
p.parse_close_binder_info(bi);
@ -248,6 +281,7 @@ static environment variable_cmd_core(parser & p, variable_kind k, bool is_protec
p.next();
type = p.parse_expr();
}
}
p.parse_close_binder_info(bi);
check_command_period_or_eof(p);
level_param_names ls;
@ -284,15 +318,56 @@ static environment variables_cmd_core(parser & p, variable_kind k, bool is_prote
optional<binder_info> bi = parse_binder_info(p, k);
buffer<name> ids;
optional<parser::local_scope> scope1;
expr type;
if (bi && bi->is_inst_implicit() && (k == variable_kind::Parameter || k == variable_kind::Variable)) {
/* instance implicit */
if (p.curr_is_identifier()) {
auto id_pos = p.pos();
name id = p.get_name_val();
p.next();
if (p.curr_is_token(get_colon_tk())) {
/* simple decl: variables [decA : decidable A] */
p.next();
ids.push_back(id);
type = p.parse_expr();
} else if (p.curr_is_token(get_rbracket_tk())) {
/* annotation update: variables [decA] */
p.parse_close_binder_info(bi);
update_local_binder_info(p, k, id, bi, pos);
if (curr_is_binder_annotation(p))
return variables_cmd_core(p, k);
else
return env;
} else {
/* anonymous : variables [decidable A] */
expr left = p.id_to_expr(id, id_pos);
id = p.mk_anonymous_inst_name();
unsigned rbp = 0;
while (rbp < p.curr_expr_lbp()) {
left = p.parse_led(left);
}
ids.push_back(id);
type = left;
}
} else {
/* anonymous : variables [forall x y, decidable (x = y)] */
name id = p.mk_anonymous_inst_name();
ids.push_back(id);
type = p.parse_expr();
}
} else {
/* non instance implicit cases */
while (p.curr_is_identifier()) {
name id = p.get_name_val();
p.next();
ids.push_back(id);
}
if (p.curr_is_token(get_colon_tk())) {
p.next();
} else {
/* binder annotation update */
/* example: variables (A) */
if (k == variable_kind::Parameter || k == variable_kind::Variable) {
p.parse_close_binder_info(bi);
for (name const & id : ids) {
@ -306,12 +381,12 @@ static environment variables_cmd_core(parser & p, variable_kind k, bool is_prote
throw parser_error("invalid variables/constants/axioms declaration, ':' expected", pos);
}
}
optional<parser::local_scope> scope1;
if (k == variable_kind::Constant || k == variable_kind::Axiom)
scope1.emplace(p);
expr type = p.parse_expr();
type = p.parse_expr();
}
p.parse_close_binder_info(bi);
level_param_names ls = to_level_param_names(collect_univ_params(type));
list<expr> ctx = p.locals_to_context();
for (auto id : ids) {

View file

@ -425,6 +425,14 @@ name parser::mk_anonymous_inst_name() {
return n;
}
bool parser::is_anonymous_inst_name(name const & n) const {
return
n.is_atomic() &&
n.is_string() &&
strlen(n.get_string()) >= strlen(g_anonymous_inst_name_prefix->get_string()) &&
memcmp(n.get_string(), g_anonymous_inst_name_prefix->get_string(), strlen(g_anonymous_inst_name_prefix->get_string())) == 0;
}
expr parser::save_pos(expr e, pos_info p) {
auto t = get_tag(e);
if (!m_pos_table.contains(t))
@ -1067,7 +1075,8 @@ void parser::parse_binder_block(buffer<expr> & r, binder_info const & bi, unsign
}
}
void parser::parse_inst_implicit_decl(buffer<expr> & r, binder_info const & bi) {
expr parser::parse_inst_implicit_decl() {
binder_info bi = mk_inst_implicit_binder_info();
auto id_pos = pos();
name id;
expr type;
@ -1093,6 +1102,12 @@ void parser::parse_inst_implicit_decl(buffer<expr> & r, binder_info const & bi)
save_identifier_info(id_pos, id);
expr local = save_pos(mk_local(id, type, bi), id_pos);
add_local(local);
return local;
}
void parser::parse_inst_implicit_decl(buffer<expr> & r) {
expr local = parse_inst_implicit_decl();
r.push_back(local);
}
@ -1115,7 +1130,7 @@ void parser::parse_binders_core(buffer<expr> & r, buffer<notation_entry> * nentr
rbp = 0;
last_block_delimited = true;
if (bi->is_inst_implicit()) {
parse_inst_implicit_decl(r, *bi);
parse_inst_implicit_decl(r);
} else {
if (simple_only || !parse_local_notation_decl(nentries))
parse_binder_block(r, *bi, rbp);

View file

@ -187,8 +187,6 @@ class parser {
tag get_tag(expr e);
expr copy_with_new_pos(expr const & e, pos_info p);
name mk_anonymous_inst_name();
parse_table const & nud() const { return get_nud_table(env()); }
parse_table const & led() const { return get_led_table(env()); }
parse_table const & tactic_nud() const { return get_tactic_nud_table(env()); }
@ -221,7 +219,8 @@ class parser {
expr parse_numeral_expr(bool user_notation = true);
expr parse_decimal_expr();
expr parse_string_expr();
void parse_inst_implicit_decl(buffer<expr> & r, binder_info const & bi);
expr parse_inst_implicit_decl();
void parse_inst_implicit_decl(buffer<expr> & r);
expr parse_binder_core(binder_info const & bi, unsigned rbp);
void parse_binder_block(buffer<expr> & r, binder_info const & bi, unsigned rbp);
void parse_binders_core(buffer<expr> & r, buffer<notation_entry> * nentries, bool & last_block_delimited, unsigned rbp, bool simple_only);
@ -286,6 +285,9 @@ public:
bool ignore_noncomputable() const { return m_ignore_noncomputable; }
void set_ignore_noncomputable() { m_ignore_noncomputable = true; }
name mk_anonymous_inst_name();
bool is_anonymous_inst_name(name const & n) const;
unsigned curr_expr_lbp() const { return curr_lbp_core(false); }
unsigned curr_tactic_lbp() const { return curr_lbp_core(true); }

View file

@ -128,6 +128,24 @@ static void collect_locals_ignoring_tactics(expr const & e, collected_locals & l
});
}
static void collect_annonymous_inst_implicit(parser const & p, collected_locals & ls) {
for (auto const & entry : p.get_local_entries()) {
if (is_local(entry.second) && !ls.contains(entry.second) && local_info(entry.second).is_inst_implicit() &&
// remark: remove the following condition condition, if we want to auto inclusion also for non anonymous ones.
p.is_anonymous_inst_name(entry.first)) {
bool ok = true;
for_each(mlocal_type(entry.second), [&](expr const & e, unsigned) {
if (!ok) return false; // stop
if (is_local(e) && !ls.contains(e))
ok = false;
return true;
});
if (ok)
ls.insert(entry.second);
}
}
}
// Collect local constants occurring in type and value, sort them, and store in ctx_ps
void collect_locals(expr const & type, expr const & value, parser const & p, buffer<expr> & ctx_ps) {
collected_locals ls;
@ -141,6 +159,7 @@ void collect_locals(expr const & type, expr const & value, parser const & p, buf
}
collect_locals_ignoring_tactics(type, ls);
collect_locals_ignoring_tactics(value, ls);
collect_annonymous_inst_implicit(p, ls);
sort_locals(ls.get_collected(), p, ctx_ps);
}
@ -187,6 +206,7 @@ levels remove_local_vars(parser const & p, levels const & ls) {
list<expr> locals_to_context(expr const & e, parser const & p) {
collected_locals ls;
collect_locals_ignoring_tactics(e, ls);
collect_annonymous_inst_implicit(p, ls);
buffer<expr> locals;
sort_locals(ls.get_collected(), p, locals);
std::reverse(locals.begin(), locals.end());

View file

@ -0,0 +1,32 @@
import algebra.group
open algebra
section
variables {A : Type} [group A]
variables {B : Type} [group B]
definition foo (a b : A) : a * b = b * a :=
sorry
definition bla (b : B) : b * 1 = b :=
sorry
print foo
print bla
end
section
variable {A : Type}
variable [group A]
variable {B : Type}
variable [group B]
definition foo2 (a b : A) : a * b = b * a :=
sorry
definition bla2 (b : B) : b * 1 = b :=
sorry
print foo2
print bla2
end

View file

@ -0,0 +1,8 @@
definition foo : ∀ {A : Type} [_inst_1 : group A] (a b : A), a * b = b * a :=
λ (A : Type) (_inst_1 : group A) (a b : A), sorry
definition bla : ∀ {B : Type} [_inst_2 : group B] (b : B), b * 1 = b :=
λ (B : Type) (_inst_2 : group B) (b : B), sorry
definition foo2 : ∀ {A : Type} [_inst_1 : group A] (a b : A), a * b = b * a :=
λ (A : Type) (_inst_1 : group A) (a b : A), sorry
definition bla2 : ∀ {B : Type} [_inst_2 : group B] (b : B), b * 1 = b :=
λ (B : Type) (_inst_2 : group B) (b : B), sorry

View file

@ -5,7 +5,7 @@ check f a b
section
parameters A B : Type
parameters {C D : Type}
parameters [e d : A]
parameters [e : A] [d : A]
check A
check B
definition g (a : A) (b : B) (c : C) : A := e