fix(library/unifier): try to generate approximate solution for flex-flex constraints before discarding them
fixes #662
This commit is contained in:
parent
d287b20018
commit
e3a0e62859
4 changed files with 136 additions and 45 deletions
|
@ -1401,6 +1401,31 @@ struct unifier_fn {
|
||||||
cs = append(aux, cs);
|
cs = append(aux, cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \see ensure_sufficient_args */
|
||||||
|
expr ensure_sufficient_args_core(expr mtype, unsigned nargs, unsigned i, constraint_seq & cs) {
|
||||||
|
if (i == nargs)
|
||||||
|
return mtype;
|
||||||
|
mtype = m_tc->ensure_pi(mtype, cs);
|
||||||
|
expr local = mk_local_for(mtype);
|
||||||
|
expr body = instantiate(binding_body(mtype), local);
|
||||||
|
return Pi(local, ensure_sufficient_args_core(body, nargs, i+1, cs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Make sure mtype is a Pi of size at least nargs.
|
||||||
|
If it is not, we use ensure_pi and (potentially) add new constaints to enforce it.
|
||||||
|
*/
|
||||||
|
expr ensure_sufficient_args(expr const & mtype, unsigned nargs, constraint_seq & cs) {
|
||||||
|
expr t = mtype;
|
||||||
|
unsigned num = 0;
|
||||||
|
while (is_pi(t)) {
|
||||||
|
num++;
|
||||||
|
t = binding_body(t);
|
||||||
|
}
|
||||||
|
if (num >= nargs)
|
||||||
|
return mtype;
|
||||||
|
return ensure_sufficient_args_core(mtype, nargs, 0, cs);
|
||||||
|
}
|
||||||
|
|
||||||
/** \brief Auxiliary functional object for implementing process_flex_rigid_core */
|
/** \brief Auxiliary functional object for implementing process_flex_rigid_core */
|
||||||
class flex_rigid_core_fn {
|
class flex_rigid_core_fn {
|
||||||
unifier_fn & u;
|
unifier_fn & u;
|
||||||
|
@ -1470,29 +1495,9 @@ struct unifier_fn {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \see ensure_sufficient_args */
|
/** \brief Make sure mtype is a Pi of size at least margs.size(). */
|
||||||
expr ensure_sufficient_args_core(expr mtype, unsigned i, constraint_seq & cs) {
|
|
||||||
if (i == margs.size())
|
|
||||||
return mtype;
|
|
||||||
mtype = tc().ensure_pi(mtype, cs);
|
|
||||||
expr local = u.mk_local_for(mtype);
|
|
||||||
expr body = instantiate(binding_body(mtype), local);
|
|
||||||
return Pi(local, ensure_sufficient_args_core(body, i+1, cs));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \brief Make sure mtype is a Pi of size at least margs.size().
|
|
||||||
If it is not, we use ensure_pi and (potentially) add new constaints to enforce it.
|
|
||||||
*/
|
|
||||||
expr ensure_sufficient_args(expr const & mtype, constraint_seq & cs) {
|
expr ensure_sufficient_args(expr const & mtype, constraint_seq & cs) {
|
||||||
expr t = mtype;
|
return u.ensure_sufficient_args(mtype, margs.size(), cs);
|
||||||
unsigned num = 0;
|
|
||||||
while (is_pi(t)) {
|
|
||||||
num++;
|
|
||||||
t = binding_body(t);
|
|
||||||
}
|
|
||||||
if (num >= margs.size())
|
|
||||||
return mtype;
|
|
||||||
return ensure_sufficient_args_core(mtype, 0, cs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1970,6 +1975,63 @@ struct unifier_fn {
|
||||||
postpone(c);
|
postpone(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auxiliary method used in process_flex_flex_approx
|
||||||
|
bool assign_flex_approx(expr const & m, expr const & v, justification const & j, constraint_seq & cs) {
|
||||||
|
lean_assert(m_config.m_discard);
|
||||||
|
buffer<expr> args;
|
||||||
|
expr const & fn = get_app_args(m, args);
|
||||||
|
lean_assert(is_metavar(fn));
|
||||||
|
expr type = mlocal_type(fn);
|
||||||
|
type = ensure_sufficient_args(type, args.size(), cs);
|
||||||
|
buffer<expr> locals;
|
||||||
|
for (expr const & a : args) {
|
||||||
|
expr local = is_local(a) ? a : mk_local_for(type);
|
||||||
|
locals.push_back(local);
|
||||||
|
type = instantiate(binding_body(type), local);
|
||||||
|
}
|
||||||
|
return assign(m, fn, locals, v, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool process_flex_flex_approx(constraint const & c) {
|
||||||
|
lean_assert(m_config.m_discard);
|
||||||
|
// Try to solve constraint
|
||||||
|
// ?M_1 t_1 ... t_n =?= ?M_2 s_1 ... s_m
|
||||||
|
// by creating a fresh metavariable ?M using common local constants.
|
||||||
|
// If can't build approximate solution, then discard constraint.
|
||||||
|
expr const & lhs = cnstr_lhs_expr(c);
|
||||||
|
expr const & rhs = cnstr_rhs_expr(c);
|
||||||
|
buffer<expr> lhs_args, rhs_args;
|
||||||
|
get_app_args(lhs, lhs_args);
|
||||||
|
get_app_args(rhs, rhs_args);
|
||||||
|
buffer<expr> shared_locals;
|
||||||
|
unsigned sz = std::min(lhs_args.size(), rhs_args.size());
|
||||||
|
unsigned i = 0;
|
||||||
|
for (; i < sz; i++) {
|
||||||
|
if (!is_local(lhs_args[i]) || !is_local(rhs_args[i]) ||
|
||||||
|
mlocal_name(lhs_args[i]) != mlocal_name(rhs_args[i]))
|
||||||
|
break;
|
||||||
|
shared_locals.push_back(lhs_args[i]);
|
||||||
|
}
|
||||||
|
constraint_seq cs;
|
||||||
|
if (optional<expr> lhs_type = infer(lhs, cs)) {
|
||||||
|
expr new_type = Pi(shared_locals, *lhs_type);
|
||||||
|
if (!has_local(new_type)) {
|
||||||
|
expr new_mvar = mk_metavar(m_ngen.next(), new_type);
|
||||||
|
expr new_val = mk_app(new_mvar, shared_locals);
|
||||||
|
justification const & j = c.get_justification();
|
||||||
|
return
|
||||||
|
assign_flex_approx(lhs, new_val, j, cs) &&
|
||||||
|
assign_flex_approx(rhs, new_val, j, cs) &&
|
||||||
|
process_constraints(cs, c.get_justification());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Failed to generate approximate solution.
|
||||||
|
// TODO(Leo): generate an error, or just ingore?
|
||||||
|
// we are currently just ignoring...
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool process_flex_flex(constraint const & c) {
|
bool process_flex_flex(constraint const & c) {
|
||||||
expr const & lhs = cnstr_lhs_expr(c);
|
expr const & lhs = cnstr_lhs_expr(c);
|
||||||
expr const & rhs = cnstr_rhs_expr(c);
|
expr const & rhs = cnstr_rhs_expr(c);
|
||||||
|
@ -1979,9 +2041,13 @@ struct unifier_fn {
|
||||||
// ?M_1 l_1 ... l_k =?= ?M_2 l_1 ... l_k ... l_n
|
// ?M_1 l_1 ... l_k =?= ?M_2 l_1 ... l_k ... l_n
|
||||||
// ?M_1 l_1 ... l_k ... l_n =?= ?M_2 l_1 ... l_k
|
// ?M_1 l_1 ... l_k ... l_n =?= ?M_2 l_1 ... l_k
|
||||||
if (!is_simple_meta(lhs) || !is_simple_meta(rhs)) {
|
if (!is_simple_meta(lhs) || !is_simple_meta(rhs)) {
|
||||||
|
if (m_config.m_discard) {
|
||||||
|
return process_flex_flex_approx(c);
|
||||||
|
} else {
|
||||||
discard(c);
|
discard(c);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
buffer<expr> lhs_args, rhs_args;
|
buffer<expr> lhs_args, rhs_args;
|
||||||
expr ml = get_app_args(lhs, lhs_args);
|
expr ml = get_app_args(lhs, lhs_args);
|
||||||
expr mr = get_app_args(rhs, rhs_args);
|
expr mr = get_app_args(rhs, rhs_args);
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
626a.lean:3:29: error: don't know how to synthesize placeholder
|
|
||||||
c : C¹
|
|
||||||
⊢ nat → Type
|
|
||||||
626a.lean:3:42: error: don't know how to synthesize placeholder
|
626a.lean:3:42: error: don't know how to synthesize placeholder
|
||||||
c : C¹
|
c : C¹
|
||||||
⊢ ?M_1
|
⊢ ?M_1
|
||||||
|
@ -12,9 +9,6 @@ c : C¹
|
||||||
remark: set 'formatter.hide_full_terms' to false to see the complete term
|
remark: set 'formatter.hide_full_terms' to false to see the complete term
|
||||||
λ (c : C¹),
|
λ (c : C¹),
|
||||||
nat.rec_on c ?M_2 ?M_3
|
nat.rec_on c ?M_2 ?M_3
|
||||||
626a.lean:8:29: error: don't know how to synthesize placeholder
|
|
||||||
c : C¹
|
|
||||||
⊢ C¹ → Type
|
|
||||||
626a.lean:8:42: error: don't know how to synthesize placeholder
|
626a.lean:8:42: error: don't know how to synthesize placeholder
|
||||||
c : C¹
|
c : C¹
|
||||||
⊢ ?M_1
|
⊢ ?M_1
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
626c.lean:2:27: error: don't know how to synthesize placeholder
|
|
||||||
c : C⁽
|
|
||||||
⊢ C⁽ → Type
|
|
||||||
626c.lean:2:40: error: don't know how to synthesize placeholder
|
626c.lean:2:40: error: don't know how to synthesize placeholder
|
||||||
c : C⁽
|
c : C⁽
|
||||||
⊢ ?M_1
|
⊢ ?M_1
|
||||||
|
@ -12,9 +9,6 @@ c : C⁽
|
||||||
remark: set 'formatter.hide_full_terms' to false to see the complete term
|
remark: set 'formatter.hide_full_terms' to false to see the complete term
|
||||||
λ (c : C⁽),
|
λ (c : C⁽),
|
||||||
nat.rec_on c ?M_2 ?M_3
|
nat.rec_on c ?M_2 ?M_3
|
||||||
626c.lean:5:27: error: don't know how to synthesize placeholder
|
|
||||||
c : α⁽
|
|
||||||
⊢ α⁽ → Type
|
|
||||||
626c.lean:5:40: error: don't know how to synthesize placeholder
|
626c.lean:5:40: error: don't know how to synthesize placeholder
|
||||||
c : α⁽
|
c : α⁽
|
||||||
⊢ ?M_1
|
⊢ ?M_1
|
||||||
|
@ -26,9 +20,6 @@ c : α⁽
|
||||||
remark: set 'formatter.hide_full_terms' to false to see the complete term
|
remark: set 'formatter.hide_full_terms' to false to see the complete term
|
||||||
λ (c : α⁽),
|
λ (c : α⁽),
|
||||||
nat.rec_on c ?M_2 ?M_3
|
nat.rec_on c ?M_2 ?M_3
|
||||||
626c.lean:8:27: error: don't know how to synthesize placeholder
|
|
||||||
c : _⁽
|
|
||||||
⊢ _⁽ → Type
|
|
||||||
626c.lean:8:40: error: don't know how to synthesize placeholder
|
626c.lean:8:40: error: don't know how to synthesize placeholder
|
||||||
c : _⁽
|
c : _⁽
|
||||||
⊢ ?M_1
|
⊢ ?M_1
|
||||||
|
@ -40,9 +31,6 @@ c : _⁽
|
||||||
remark: set 'formatter.hide_full_terms' to false to see the complete term
|
remark: set 'formatter.hide_full_terms' to false to see the complete term
|
||||||
λ (c : _⁽),
|
λ (c : _⁽),
|
||||||
nat.rec_on c ?M_2 ?M_3
|
nat.rec_on c ?M_2 ?M_3
|
||||||
626c.lean:11:28: error: don't know how to synthesize placeholder
|
|
||||||
c : C.⁽
|
|
||||||
⊢ C.⁽ → Type
|
|
||||||
626c.lean:11:41: error: don't know how to synthesize placeholder
|
626c.lean:11:41: error: don't know how to synthesize placeholder
|
||||||
c : C.⁽
|
c : C.⁽
|
||||||
⊢ ?M_1
|
⊢ ?M_1
|
||||||
|
@ -54,9 +42,6 @@ c : C.⁽
|
||||||
remark: set 'formatter.hide_full_terms' to false to see the complete term
|
remark: set 'formatter.hide_full_terms' to false to see the complete term
|
||||||
λ (c : C.⁽),
|
λ (c : C.⁽),
|
||||||
nat.rec_on c ?M_2 ?M_3
|
nat.rec_on c ?M_2 ?M_3
|
||||||
626c.lean:14:29: error: don't know how to synthesize placeholder
|
|
||||||
c : C⁽C⁽
|
|
||||||
⊢ C⁽C⁽ → Type
|
|
||||||
626c.lean:14:42: error: don't know how to synthesize placeholder
|
626c.lean:14:42: error: don't know how to synthesize placeholder
|
||||||
c : C⁽C⁽
|
c : C⁽C⁽
|
||||||
⊢ ?M_1
|
⊢ ?M_1
|
||||||
|
|
46
tests/lean/run/662.lean
Normal file
46
tests/lean/run/662.lean
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
open nat
|
||||||
|
|
||||||
|
inductive type : Type :=
|
||||||
|
| Nat : type
|
||||||
|
| Func : type → type → type
|
||||||
|
|
||||||
|
open type
|
||||||
|
|
||||||
|
section var
|
||||||
|
variable {var : type → Type}
|
||||||
|
|
||||||
|
inductive term : type → Type :=
|
||||||
|
| Var : ∀ {t}, var t → term t
|
||||||
|
| Const : nat → term Nat
|
||||||
|
| Plus : term Nat → term Nat → term Nat
|
||||||
|
| Abs : ∀ {dom ran}, (var dom → term ran) → term (Func dom ran)
|
||||||
|
| App : ∀ {dom ran}, term (Func dom ran) → term dom → term ran
|
||||||
|
| Let : ∀ {t1 t2}, term t1 → (var t1 → term t2) → term t2
|
||||||
|
end var
|
||||||
|
|
||||||
|
open term
|
||||||
|
|
||||||
|
definition Term t := Π (var : type → Type), @term var t
|
||||||
|
open unit
|
||||||
|
|
||||||
|
definition count_vars : Π {t : type}, @term (λ x, unit) t -> nat
|
||||||
|
| count_vars (Var _) := 1
|
||||||
|
| count_vars (Const _) := 0
|
||||||
|
| count_vars (Plus e1 e2) := count_vars e1 + count_vars e2
|
||||||
|
| count_vars (Abs e1) := count_vars (e1 star)
|
||||||
|
| count_vars (App e1 e2) := count_vars e1 + count_vars e2
|
||||||
|
| count_vars (Let e1 e2) := count_vars e1 + count_vars (e2 star)
|
||||||
|
|
||||||
|
definition var (t : type) : @term (λ x, unit) t :=
|
||||||
|
Var star
|
||||||
|
|
||||||
|
example : count_vars (App (App (var (Func Nat (Func Nat Nat))) (var Nat)) (var Nat)) = 3 :=
|
||||||
|
rfl
|
||||||
|
|
||||||
|
definition count_vars2 : Π {t : type}, @term (λ x, unit) t -> nat
|
||||||
|
| _ (Var _) := 1
|
||||||
|
| _ (Const _) := 0
|
||||||
|
| _ (Plus e1 e2) := count_vars2 e1 + count_vars2 e2
|
||||||
|
| _ (Abs e1) := count_vars2 (e1 star)
|
||||||
|
| _ (App e1 e2) := count_vars2 e1 + count_vars2 e2
|
||||||
|
| _ (Let e1 e2) := count_vars2 e1 + count_vars2 (e2 star)
|
Loading…
Reference in a new issue