feat(frontends/lean): add 'universe variable' command
We can declare variables anywhere. So, we must also be able do declare "universe" variables anywhere. Here is a minimal example that requires this feature ``` -- We want A and B to be in the same universe universe variable l variable A : Type.{l} variable B : Type.{l} definition tst := A = B ``` The following doesn't work because A and B are in different universes ``` variable A : Type variable B : Type definition tst := A = B ``` The following works, but tst is not universe polymorphic, since l is one *fixed* global universe ``` universe l variable A : Type.{l} variable B : Type.{l} definition tst := A = B ```
This commit is contained in:
parent
6a40f80612
commit
ca632cca13
9 changed files with 70 additions and 16 deletions
|
@ -24,8 +24,8 @@ Author: Leonardo de Moura
|
||||||
#include "frontends/lean/tokens.h"
|
#include "frontends/lean/tokens.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
static environment declare_universe(parser & p, environment env, name const & n) {
|
static environment declare_universe(parser & p, environment env, name const & n, bool local) {
|
||||||
if (in_section_or_context(env)) {
|
if (in_section_or_context(env) || local) {
|
||||||
p.add_local_level(n, mk_param_univ(n));
|
p.add_local_level(n, mk_param_univ(n));
|
||||||
} else {
|
} else {
|
||||||
name const & ns = get_namespace(env);
|
name const & ns = get_namespace(env);
|
||||||
|
@ -37,23 +37,37 @@ static environment declare_universe(parser & p, environment env, name const & n)
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
environment universe_cmd(parser & p) {
|
static environment universes_cmd_core(parser & p, bool local) {
|
||||||
name n = p.check_id_next("invalid 'universe' command, identifier expected");
|
|
||||||
return declare_universe(p, p.env(), n);
|
|
||||||
}
|
|
||||||
|
|
||||||
environment universes_cmd(parser & p) {
|
|
||||||
if (!p.curr_is_identifier())
|
if (!p.curr_is_identifier())
|
||||||
throw parser_error("invalid 'universes' command, identifier expected", p.pos());
|
throw parser_error("invalid 'universes' command, identifier expected", p.pos());
|
||||||
environment env = p.env();
|
environment env = p.env();
|
||||||
while (p.curr_is_identifier()) {
|
while (p.curr_is_identifier()) {
|
||||||
name n = p.get_name_val();
|
name n = p.get_name_val();
|
||||||
p.next();
|
p.next();
|
||||||
env = declare_universe(p, env, n);
|
env = declare_universe(p, env, n, local);
|
||||||
}
|
}
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static environment universe_cmd(parser & p) {
|
||||||
|
if (p.curr_is_token(get_variables_tk())) {
|
||||||
|
p.next();
|
||||||
|
return universes_cmd_core(p, true);
|
||||||
|
} else {
|
||||||
|
bool local = false;
|
||||||
|
if (p.curr_is_token(get_variable_tk())) {
|
||||||
|
p.next();
|
||||||
|
local = true;
|
||||||
|
}
|
||||||
|
name n = p.check_id_next("invalid 'universe' command, identifier expected");
|
||||||
|
return declare_universe(p, p.env(), n, local);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static environment universes_cmd(parser & p) {
|
||||||
|
return universes_cmd_core(p, false);
|
||||||
|
}
|
||||||
|
|
||||||
bool parse_univ_params(parser & p, buffer<name> & ps) {
|
bool parse_univ_params(parser & p, buffer<name> & ps) {
|
||||||
if (p.curr_is_token(get_llevel_curly_tk())) {
|
if (p.curr_is_token(get_llevel_curly_tk())) {
|
||||||
p.next();
|
p.next();
|
||||||
|
@ -383,7 +397,7 @@ environment definition_cmd_core(parser & p, bool is_theorem, bool is_opaque, boo
|
||||||
value = Fun_as_is(section_value_ps, value, p);
|
value = Fun_as_is(section_value_ps, value, p);
|
||||||
update_univ_parameters(ls_buffer, collect_univ_params(value, collect_univ_params(type)), p);
|
update_univ_parameters(ls_buffer, collect_univ_params(value, collect_univ_params(type)), p);
|
||||||
ls = to_list(ls_buffer.begin(), ls_buffer.end());
|
ls = to_list(ls_buffer.begin(), ls_buffer.end());
|
||||||
levels section_ls = collect_section_nonvar_levels(p, ls);
|
levels section_ls = collect_local_nonvar_levels(p, ls);
|
||||||
remove_section_variables(p, section_ps);
|
remove_section_variables(p, section_ps);
|
||||||
if (!section_ps.empty()) {
|
if (!section_ps.empty()) {
|
||||||
expr ref = mk_section_local_ref(real_n, section_ls, section_ps);
|
expr ref = mk_section_local_ref(real_n, section_ls, section_ps);
|
||||||
|
|
|
@ -608,7 +608,7 @@ struct inductive_cmd_fn {
|
||||||
buffer<expr> section_params_only(section_params);
|
buffer<expr> section_params_only(section_params);
|
||||||
remove_section_variables(m_p, section_params_only);
|
remove_section_variables(m_p, section_params_only);
|
||||||
// Create aliases/local refs
|
// Create aliases/local refs
|
||||||
levels section_levels = collect_section_nonvar_levels(m_p, ls);
|
levels section_levels = collect_local_nonvar_levels(m_p, ls);
|
||||||
for (auto & d : decls) {
|
for (auto & d : decls) {
|
||||||
name d_name = inductive_decl_name(d);
|
name d_name = inductive_decl_name(d);
|
||||||
name d_short_name(d_name.get_string());
|
name d_short_name(d_name.get_string());
|
||||||
|
|
|
@ -75,7 +75,7 @@ void init_token_table(token_table & t) {
|
||||||
{"using", 0}, {"|", 0}, {"!", g_max_prec}, {"with", 0}, {"...", 0}, {",", 0},
|
{"using", 0}, {"|", 0}, {"!", g_max_prec}, {"with", 0}, {"...", 0}, {",", 0},
|
||||||
{".", 0}, {":", 0}, {"::", 0}, {"calc", 0}, {":=", 0}, {"--", 0}, {"#", 0},
|
{".", 0}, {":", 0}, {"::", 0}, {"calc", 0}, {":=", 0}, {"--", 0}, {"#", 0},
|
||||||
{"(*", 0}, {"/-", 0}, {"begin", g_max_prec}, {"proof", g_max_prec}, {"qed", 0}, {"@", g_max_prec},
|
{"(*", 0}, {"/-", 0}, {"begin", g_max_prec}, {"proof", g_max_prec}, {"qed", 0}, {"@", g_max_prec},
|
||||||
{"sorry", g_max_prec}, {"+", g_plus_prec}, {g_cup, g_cup_prec}, {"->", g_arrow_prec},
|
{"sorry", g_max_prec}, {"+", g_plus_prec}, {g_cup, g_cup_prec}, {"->", g_arrow_prec}, {"local", 0},
|
||||||
{nullptr, 0}};
|
{nullptr, 0}};
|
||||||
|
|
||||||
char const * commands[] =
|
char const * commands[] =
|
||||||
|
|
|
@ -65,6 +65,7 @@ static name * g_definition = nullptr;
|
||||||
static name * g_theorem = nullptr;
|
static name * g_theorem = nullptr;
|
||||||
static name * g_axiom = nullptr;
|
static name * g_axiom = nullptr;
|
||||||
static name * g_variable = nullptr;
|
static name * g_variable = nullptr;
|
||||||
|
static name * g_variables = nullptr;
|
||||||
static name * g_opaque = nullptr;
|
static name * g_opaque = nullptr;
|
||||||
static name * g_instance = nullptr;
|
static name * g_instance = nullptr;
|
||||||
static name * g_priority = nullptr;
|
static name * g_priority = nullptr;
|
||||||
|
@ -148,6 +149,7 @@ void initialize_tokens() {
|
||||||
g_opaque = new name("opaque");
|
g_opaque = new name("opaque");
|
||||||
g_axiom = new name("axiom");
|
g_axiom = new name("axiom");
|
||||||
g_variable = new name("variable");
|
g_variable = new name("variable");
|
||||||
|
g_variables = new name("variables");
|
||||||
g_instance = new name("[instance]");
|
g_instance = new name("[instance]");
|
||||||
g_priority = new name("[priority");
|
g_priority = new name("[priority");
|
||||||
g_coercion = new name("[coercion]");
|
g_coercion = new name("[coercion]");
|
||||||
|
@ -193,6 +195,7 @@ void finalize_tokens() {
|
||||||
delete g_theorem;
|
delete g_theorem;
|
||||||
delete g_opaque;
|
delete g_opaque;
|
||||||
delete g_axiom;
|
delete g_axiom;
|
||||||
|
delete g_variables;
|
||||||
delete g_variable;
|
delete g_variable;
|
||||||
delete g_instance;
|
delete g_instance;
|
||||||
delete g_priority;
|
delete g_priority;
|
||||||
|
@ -312,6 +315,7 @@ name const & get_definition_tk() { return *g_definition; }
|
||||||
name const & get_theorem_tk() { return *g_theorem; }
|
name const & get_theorem_tk() { return *g_theorem; }
|
||||||
name const & get_axiom_tk() { return *g_axiom; }
|
name const & get_axiom_tk() { return *g_axiom; }
|
||||||
name const & get_variable_tk() { return *g_variable; }
|
name const & get_variable_tk() { return *g_variable; }
|
||||||
|
name const & get_variables_tk() { return *g_variables; }
|
||||||
name const & get_opaque_tk() { return *g_opaque; }
|
name const & get_opaque_tk() { return *g_opaque; }
|
||||||
name const & get_instance_tk() { return *g_instance; }
|
name const & get_instance_tk() { return *g_instance; }
|
||||||
name const & get_priority_tk() { return *g_priority; }
|
name const & get_priority_tk() { return *g_priority; }
|
||||||
|
|
|
@ -67,6 +67,7 @@ name const & get_definition_tk();
|
||||||
name const & get_theorem_tk();
|
name const & get_theorem_tk();
|
||||||
name const & get_axiom_tk();
|
name const & get_axiom_tk();
|
||||||
name const & get_variable_tk();
|
name const & get_variable_tk();
|
||||||
|
name const & get_variables_tk();
|
||||||
name const & get_opaque_tk();
|
name const & get_opaque_tk();
|
||||||
name const & get_instance_tk();
|
name const & get_instance_tk();
|
||||||
name const & get_priority_tk();
|
name const & get_priority_tk();
|
||||||
|
|
|
@ -60,8 +60,8 @@ void sort_section_params(expr_struct_set const & locals, parser const & p, buffe
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the levels in \c ls that are defined in the section
|
// Return the local levels in \c ls that are not associated with variables
|
||||||
levels collect_section_nonvar_levels(parser & p, level_param_names const & ls) {
|
levels collect_local_nonvar_levels(parser & p, level_param_names const & ls) {
|
||||||
buffer<level> section_ls_buffer;
|
buffer<level> section_ls_buffer;
|
||||||
for (name const & l : ls) {
|
for (name const & l : ls) {
|
||||||
if (p.get_local_level_index(l) && !p.is_local_level_variable(l))
|
if (p.get_local_level_index(l) && !p.is_local_level_variable(l))
|
||||||
|
|
|
@ -22,8 +22,10 @@ void check_atomic(name const & n);
|
||||||
void check_in_section_or_context(parser const & p);
|
void check_in_section_or_context(parser const & p);
|
||||||
bool is_root_namespace(name const & n);
|
bool is_root_namespace(name const & n);
|
||||||
name remove_root_prefix(name const & n);
|
name remove_root_prefix(name const & n);
|
||||||
/** \brief Return the levels in \c ls that are defined in the section, but are not tagged as variables. */
|
/** \brief Return the local levels in \c ls that are not tagged as variables.
|
||||||
levels collect_section_nonvar_levels(parser & p, level_param_names const & ls);
|
A local level is tagged as variable if it associated with a variable.
|
||||||
|
*/
|
||||||
|
levels collect_local_nonvar_levels(parser & p, level_param_names const & ls);
|
||||||
/** \brief Collect local (section) constants occurring in type and value, sort them, and store in section_ps */
|
/** \brief Collect local (section) constants occurring in type and value, sort them, and store in section_ps */
|
||||||
void collect_section_locals(expr const & type, expr const & value, parser const & p, buffer<expr> & section_ps);
|
void collect_section_locals(expr const & type, expr const & value, parser const & p, buffer<expr> & section_ps);
|
||||||
/** \brief Copy the local parameters to \c section_ps, then sort \c section_ps (using the order in which they were declared). */
|
/** \brief Copy the local parameters to \c section_ps, then sort \c section_ps (using the order in which they were declared). */
|
||||||
|
|
28
tests/lean/univ_vars.lean
Normal file
28
tests/lean/univ_vars.lean
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import logic
|
||||||
|
set_option pp.universes true
|
||||||
|
|
||||||
|
universe u
|
||||||
|
variable A : Type.{u}
|
||||||
|
|
||||||
|
definition id1 (a : A) : A := a
|
||||||
|
check @id1
|
||||||
|
|
||||||
|
variable B : Type
|
||||||
|
|
||||||
|
definition id2 (a : B) : B := a
|
||||||
|
check @id2
|
||||||
|
|
||||||
|
universe variable k
|
||||||
|
variable C : Type.{k}
|
||||||
|
|
||||||
|
definition id3 (a : C) := a
|
||||||
|
|
||||||
|
check @id3
|
||||||
|
|
||||||
|
universe variables l m
|
||||||
|
variable A₁ : Type.{l}
|
||||||
|
variable A₂ : Type.{l}
|
||||||
|
definition foo (a₁ : A₁) (a₂ : A₂) := a₁ == a₂
|
||||||
|
check @foo
|
||||||
|
|
||||||
|
check Type.{m}
|
5
tests/lean/univ_vars.lean.expected.out
Normal file
5
tests/lean/univ_vars.lean.expected.out
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
id1 : Π (A : Type.{u}), A → A
|
||||||
|
id2.{l_2} : Π (B : Type.{l_2}), B → B
|
||||||
|
id3.{k} : Π (C : Type.{k}), C → C
|
||||||
|
foo.{l} : Π (A₁ A₂ : Type.{l}), A₁ → A₂ → Prop
|
||||||
|
Type.{m} : Type.{succ m}
|
Loading…
Reference in a new issue