feat(frontends/lean): support for nary-tuples, improve notation for non-dependent tuples, add support in the elaborator for sigma types
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
5c991f8fbf
commit
cc96b50644
6 changed files with 76 additions and 39 deletions
|
@ -8,6 +8,6 @@ Author: Leonardo de Moura
|
||||||
#include <limits>
|
#include <limits>
|
||||||
namespace lean {
|
namespace lean {
|
||||||
constexpr unsigned g_arrow_precedence = 25;
|
constexpr unsigned g_arrow_precedence = 25;
|
||||||
constexpr unsigned g_cartesian_product_precedence = 25;
|
constexpr unsigned g_cartesian_product_precedence = 30;
|
||||||
constexpr unsigned g_app_precedence = std::numeric_limits<unsigned>::max();
|
constexpr unsigned g_app_precedence = std::numeric_limits<unsigned>::max();
|
||||||
}
|
}
|
||||||
|
|
|
@ -857,25 +857,33 @@ expr parser_imp::parse_tuple() {
|
||||||
auto p = pos();
|
auto p = pos();
|
||||||
next();
|
next();
|
||||||
buffer<expr> args;
|
buffer<expr> args;
|
||||||
args.push_back(parse_expr());
|
expr first = parse_expr();
|
||||||
|
expr type;
|
||||||
|
if (curr_is_colon()) {
|
||||||
|
next();
|
||||||
|
type = first;
|
||||||
|
args.push_back(parse_expr());
|
||||||
|
} else {
|
||||||
|
args.push_back(first);
|
||||||
|
type = save(mk_placeholder(), p);
|
||||||
|
}
|
||||||
while (curr_is_comma()) {
|
while (curr_is_comma()) {
|
||||||
next();
|
next();
|
||||||
args.push_back(parse_expr());
|
args.push_back(parse_expr());
|
||||||
}
|
}
|
||||||
unsigned num = args.size();
|
unsigned num = args.size();
|
||||||
if (num < 3)
|
if (num < 2)
|
||||||
throw parser_error("invalid tuple/pair, it must have at least three arguments", p);
|
throw parser_error("invalid tuple/pair, it must have at least two arguments", p);
|
||||||
expr t = args[num-1];
|
if (num == 2) {
|
||||||
if (num == 3) {
|
return save(mk_pair(args[num-2], args[num-1], type), p);
|
||||||
return save(mk_pair(args[num-3], args[num-2], t), p);
|
|
||||||
} else {
|
} else {
|
||||||
expr r = save(mk_pair(args[num-3], args[num-2], save(mk_placeholder(), p)), p);
|
expr r = save(mk_pair(args[num-2], args[num-1], save(mk_placeholder(), p)), p);
|
||||||
unsigned i = num-3;
|
unsigned i = num-2;
|
||||||
while (true) {
|
while (true) {
|
||||||
lean_assert(i > 0);
|
lean_assert(i > 0);
|
||||||
--i;
|
--i;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
return save(mk_pair(args[0], r, t), p);
|
return save(mk_pair(args[0], r, type), p);
|
||||||
} else {
|
} else {
|
||||||
r = save(mk_pair(args[i], r, save(mk_placeholder(), p)), p);
|
r = save(mk_pair(args[i], r, save(mk_placeholder(), p)), p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1117,15 +1117,23 @@ class pp_fn {
|
||||||
result pp_tuple(expr a, unsigned depth) {
|
result pp_tuple(expr a, unsigned depth) {
|
||||||
buffer<expr> args;
|
buffer<expr> args;
|
||||||
args.push_back(pair_first(a));
|
args.push_back(pair_first(a));
|
||||||
while (is_pair(pair_second(a))) {
|
expr t = pair_type(a);
|
||||||
|
bool cartesian = is_cartesian(t);
|
||||||
|
while (is_pair(pair_second(a)) && !has_metavar(pair_second(a))) {
|
||||||
a = pair_second(a);
|
a = pair_second(a);
|
||||||
|
if (!is_cartesian(pair_type(a)))
|
||||||
|
cartesian = false;
|
||||||
args.push_back(pair_first(a));
|
args.push_back(pair_first(a));
|
||||||
}
|
}
|
||||||
args.push_back(pair_second(a));
|
args.push_back(pair_second(a));
|
||||||
args.push_back(pair_type(a));
|
|
||||||
unsigned indent = 6;
|
unsigned indent = 6;
|
||||||
format r_format = g_tuple_fmt;
|
format r_format = g_tuple_fmt;
|
||||||
unsigned r_weight = 1;
|
unsigned r_weight = 1;
|
||||||
|
if (!cartesian) {
|
||||||
|
auto t_r = pp_child(t, depth);
|
||||||
|
r_format += nest(indent, compose(line(), format{t_r.first, space(), colon()}));
|
||||||
|
r_weight += t_r.second;
|
||||||
|
}
|
||||||
for (unsigned i = 0; i < args.size(); i++) {
|
for (unsigned i = 0; i < args.size(); i++) {
|
||||||
auto arg_r = pp_child(args[i], depth);
|
auto arg_r = pp_child(args[i], depth);
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
|
|
|
@ -1188,7 +1188,7 @@ class elaborator::imp {
|
||||||
m_case_splits.push_back(std::move(new_cs));
|
m_case_splits.push_back(std::move(new_cs));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
} else if (is_lambda(b) || is_pi(b)) {
|
} else if (is_abstraction(b)) {
|
||||||
imitate_abstraction(a, b, c);
|
imitate_abstraction(a, b, c);
|
||||||
return true;
|
return true;
|
||||||
} else if (is_app(b) && !has_metavar(arg(b, 0))) {
|
} else if (is_app(b) && !has_metavar(arg(b, 0))) {
|
||||||
|
@ -1472,7 +1472,7 @@ class elaborator::imp {
|
||||||
push_new_constraint(eq, new_ctx, abst_body(a), abst_body(b), new_jst);
|
push_new_constraint(eq, new_ctx, abst_body(a), abst_body(b), new_jst);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
case expr_kind::Lambda: {
|
case expr_kind::Lambda: case expr_kind::Sigma: {
|
||||||
justification new_jst(new destruct_justification(c));
|
justification new_jst(new destruct_justification(c));
|
||||||
push_new_eq_constraint(ctx, abst_domain(a), abst_domain(b), new_jst);
|
push_new_eq_constraint(ctx, abst_domain(a), abst_domain(b), new_jst);
|
||||||
context new_ctx = extend(ctx, abst_name(a), abst_domain(a));
|
context new_ctx = extend(ctx, abst_name(a), abst_domain(a));
|
||||||
|
@ -1534,6 +1534,22 @@ class elaborator::imp {
|
||||||
m_conflict = mk_failure_justification(c);
|
m_conflict = mk_failure_justification(c);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
case expr_kind::Proj:
|
||||||
|
if (proj_first(a) != proj_first(b)) {
|
||||||
|
m_conflict = mk_failure_justification(c);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
justification new_jst(new destruct_justification(c));
|
||||||
|
push_new_eq_constraint(ctx, proj_arg(a), proj_arg(b), new_jst);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case expr_kind::Pair: {
|
||||||
|
justification new_jst(new destruct_justification(c));
|
||||||
|
push_new_eq_constraint(ctx, pair_first(a), pair_first(b), new_jst);
|
||||||
|
push_new_eq_constraint(ctx, pair_second(a), pair_second(b), new_jst);
|
||||||
|
push_new_eq_constraint(ctx, pair_type(a), pair_type(b), new_jst);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
case expr_kind::App:
|
case expr_kind::App:
|
||||||
if (!is_meta_app(a) && !is_meta_app(b)) {
|
if (!is_meta_app(a) && !is_meta_app(b)) {
|
||||||
if (num_args(a) == num_args(b)) {
|
if (num_args(a) == num_args(b)) {
|
||||||
|
@ -1550,7 +1566,8 @@ class elaborator::imp {
|
||||||
case expr_kind::Let:
|
case expr_kind::Let:
|
||||||
lean_unreachable(); // LCOV_EXCL_LINE
|
lean_unreachable(); // LCOV_EXCL_LINE
|
||||||
return true;
|
return true;
|
||||||
default:
|
case expr_kind::Pi: case expr_kind::Lambda:
|
||||||
|
case expr_kind::Sigma: case expr_kind::MetaVar:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
check sig x : Nat, x > 0
|
check sig x : Nat, x > 0
|
||||||
check tuple 10, 20, (Nat # Nat)
|
check tuple 10, 20
|
||||||
check tuple 10, true, (Nat # Nat)
|
check tuple 10, true
|
||||||
check tuple true, 20, (Nat # Nat)
|
check tuple true, 20
|
||||||
check tuple true, 20, (Bool # Nat)
|
check tuple (Bool # Nat) : true, 20
|
||||||
check tuple true, true, (Bool # Bool)
|
check tuple true, true
|
||||||
check tuple true, true, (Bool ⨯ Bool)
|
check tuple Bool ⨯ Bool : true, true
|
||||||
variable a : Nat
|
variable a : Nat
|
||||||
axiom Ha : 1 ≤ a
|
axiom Ha : 1 ≤ a
|
||||||
definition NZ : Type := sig x : Nat, 1 ≤ x
|
definition NZ : Type := sig x : Nat, 1 ≤ x
|
||||||
check NZ
|
check NZ
|
||||||
check tuple a, Ha, NZ
|
check tuple NZ : a, Ha
|
||||||
|
check tuple Nat # Nat : true, 20
|
||||||
|
check tuple Bool # Bool : true, 20
|
||||||
|
|
|
@ -1,24 +1,26 @@
|
||||||
Set: pp::colors
|
Set: pp::colors
|
||||||
Set: pp::unicode
|
Set: pp::unicode
|
||||||
sig x : ℕ, x > 0 : Type
|
sig x : ℕ, x > 0 : Type
|
||||||
tuple 10, 20, (ℕ ⨯ ℕ) : ℕ ⨯ ℕ
|
tuple 10, 20 : ℕ ⨯ ℕ
|
||||||
sig2.lean:3:6: error: type mismatch in the 2nd argument of the pair
|
tuple 10, ⊤ : ℕ ⨯ Bool
|
||||||
tuple 10, ⊤, (ℕ ⨯ ℕ)
|
tuple ⊤, 20 : Bool ⨯ ℕ
|
||||||
Pair type:
|
tuple ⊤, 20 : Bool ⨯ ℕ
|
||||||
ℕ ⨯ ℕ
|
tuple ⊤, ⊤ : Bool ⨯ Bool
|
||||||
Argument type:
|
tuple ⊤, ⊤ : Bool ⨯ Bool
|
||||||
Bool
|
|
||||||
sig2.lean:4:6: error: type mismatch in the 1st argument of the pair
|
|
||||||
tuple ⊤, 20, (ℕ ⨯ ℕ)
|
|
||||||
Pair type:
|
|
||||||
ℕ ⨯ ℕ
|
|
||||||
Argument type:
|
|
||||||
Bool
|
|
||||||
tuple ⊤, 20, (Bool ⨯ ℕ) : Bool ⨯ ℕ
|
|
||||||
tuple ⊤, ⊤, (Bool ⨯ Bool) : Bool ⨯ Bool
|
|
||||||
tuple ⊤, ⊤, (Bool ⨯ Bool) : Bool ⨯ Bool
|
|
||||||
Assumed: a
|
Assumed: a
|
||||||
Assumed: Ha
|
Assumed: Ha
|
||||||
Defined: NZ
|
Defined: NZ
|
||||||
NZ : Type
|
NZ : Type
|
||||||
tuple a, Ha, NZ : sig x : ℕ, 1 ≤ x
|
tuple NZ : a, Ha : sig x : ℕ, 1 ≤ x
|
||||||
|
sig2.lean:13:6: error: type mismatch in the 1st argument of the pair
|
||||||
|
tuple ⊤, 20
|
||||||
|
Pair type:
|
||||||
|
ℕ ⨯ ℕ
|
||||||
|
Argument type:
|
||||||
|
Bool
|
||||||
|
sig2.lean:14:6: error: type mismatch in the 2nd argument of the pair
|
||||||
|
tuple ⊤, 20
|
||||||
|
Pair type:
|
||||||
|
Bool ⨯ Bool
|
||||||
|
Argument type:
|
||||||
|
ℕ
|
||||||
|
|
Loading…
Reference in a new issue