fix(frontends/lean/elaborator): closes #771

Produce nicer error message when type/goal is a metavariable and
universe metavariables have already been instantiated with universe
parameters.
This commit is contained in:
Leonardo de Moura 2015-08-07 20:31:43 +01:00
parent 6a079fdd2d
commit 5568085ab9
6 changed files with 52 additions and 97 deletions

View file

@ -1148,7 +1148,8 @@ constraint elaborator::mk_equations_cnstr(expr const & m, expr const & eqns) {
name_generator && ngen) { name_generator && ngen) {
substitution new_s = s; substitution new_s = s;
expr new_eqns = new_s.instantiate_all(eqns); expr new_eqns = new_s.instantiate_all(eqns);
new_eqns = solve_unassigned_mvars(new_s, new_eqns); bool reject_type_is_meta = false;
new_eqns = solve_unassigned_mvars(new_s, new_eqns, reject_type_is_meta);
if (display_unassigned_mvars(new_eqns, new_s)) if (display_unassigned_mvars(new_eqns, new_s))
return lazy_list<constraints>(); return lazy_list<constraints>();
type_checker_ptr tc = mk_type_checker(_env, std::move(ngen)); type_checker_ptr tc = mk_type_checker(_env, std::move(ngen));
@ -1930,7 +1931,9 @@ bool elaborator::try_using_begin_end(substitution & subst, expr const & mvar, pr
} }
} }
void elaborator::solve_unassigned_mvar(substitution & subst, expr mvar, name_set & visited) { // The parameters univs_fixed is true if the elaborator has instantiated the universe metavariables with universe parameters.
// See issue #771
void elaborator::solve_unassigned_mvar(substitution & subst, expr mvar, name_set & visited, bool reject_type_is_meta) {
if (visited.contains(mlocal_name(mvar))) if (visited.contains(mlocal_name(mvar)))
return; return;
visited.insert(mlocal_name(mvar)); visited.insert(mlocal_name(mvar));
@ -1941,7 +1944,11 @@ void elaborator::solve_unassigned_mvar(substitution & subst, expr mvar, name_set
// TODO(Leo): we are discarding constraints here // TODO(Leo): we are discarding constraints here
expr type = m_tc->infer(*meta).first; expr type = m_tc->infer(*meta).first;
// first solve unassigned metavariables in type // first solve unassigned metavariables in type
type = solve_unassigned_mvars(subst, type, visited); type = solve_unassigned_mvars(subst, type, visited, reject_type_is_meta);
if (reject_type_is_meta && is_meta(type)) {
throw_elaborator_exception("failed to synthesize placeholder, type is a unknown (i.e., it is a metavariable) "
"(solution: provide type explicitly)", mvar);
}
proof_state ps = to_proof_state(*meta, type, subst, m_ngen.mk_child()); proof_state ps = to_proof_state(*meta, type, subst, m_ngen.mk_child());
if (auto pre_tac = get_pre_tactic_for(mvar)) { if (auto pre_tac = get_pre_tactic_for(mvar)) {
if (is_begin_end_annotation(*pre_tac)) { if (is_begin_end_annotation(*pre_tac)) {
@ -2027,17 +2034,17 @@ static void visit_unassigned_mvars(expr const & e, std::function<void(expr const
visit(e); visit(e);
} }
expr elaborator::solve_unassigned_mvars(substitution & subst, expr e, name_set & visited) { expr elaborator::solve_unassigned_mvars(substitution & subst, expr e, name_set & visited, bool reject_type_is_meta) {
e = subst.instantiate(e); e = subst.instantiate(e);
visit_unassigned_mvars(e, [&](expr const & mvar) { visit_unassigned_mvars(e, [&](expr const & mvar) {
solve_unassigned_mvar(subst, mvar, visited); solve_unassigned_mvar(subst, mvar, visited, reject_type_is_meta);
}); });
return subst.instantiate(e); return subst.instantiate(e);
} }
expr elaborator::solve_unassigned_mvars(substitution & subst, expr const & e) { expr elaborator::solve_unassigned_mvars(substitution & subst, expr const & e, bool reject_type_is_meta) {
name_set visited; name_set visited;
return solve_unassigned_mvars(subst, e, visited); return solve_unassigned_mvars(subst, e, visited, reject_type_is_meta);
} }
bool elaborator::display_unassigned_mvars(expr const & e, substitution const & s) { bool elaborator::display_unassigned_mvars(expr const & e, substitution const & s) {
@ -2090,19 +2097,20 @@ void elaborator::check_sort_assignments(substitution const & s) {
} }
/** \brief Apply substitution and solve remaining metavariables using tactics. */ /** \brief Apply substitution and solve remaining metavariables using tactics. */
expr elaborator::apply(substitution & s, expr const & e, name_set & univ_params, buffer<name> & new_params) { expr elaborator::apply(substitution & s, expr const & e, name_set & univ_params, buffer<name> & new_params, bool is_def_value) {
expr r = s.instantiate(e); expr r = s.instantiate(e);
if (has_univ_metavar(r)) if (has_univ_metavar(r))
r = univ_metavars_to_params(env(), lls(), s, univ_params, new_params, r); r = univ_metavars_to_params(env(), lls(), s, univ_params, new_params, r);
r = solve_unassigned_mvars(s, r); bool reject_type_is_meta = is_def_value;
r = solve_unassigned_mvars(s, r, reject_type_is_meta);
display_unassigned_mvars(r, s); display_unassigned_mvars(r, s);
return r; return r;
} }
std::tuple<expr, level_param_names> elaborator::apply(substitution & s, expr const & e) { std::tuple<expr, level_param_names> elaborator::apply(substitution & s, expr const & e, bool is_def_value) {
auto ps = collect_univ_params(e); auto ps = collect_univ_params(e);
buffer<name> new_ps; buffer<name> new_ps;
expr r = apply(s, e, ps, new_ps); expr r = apply(s, e, ps, new_ps, is_def_value);
return std::make_tuple(r, to_list(new_ps.begin(), new_ps.end())); return std::make_tuple(r, to_list(new_ps.begin(), new_ps.end()));
} }
@ -2153,7 +2161,8 @@ auto elaborator::operator()(list<expr> const & ctx, expr const & e, bool _ensure
auto p = solve(cs).pull(); auto p = solve(cs).pull();
lean_assert(p); lean_assert(p);
substitution s = p->first.first; substitution s = p->first.first;
auto result = apply(s, r); bool is_value = false;
auto result = apply(s, r, is_value);
check_sort_assignments(s); check_sort_assignments(s);
instantiate_info(s); instantiate_info(s);
check_used_local_tactic_hints(); check_used_local_tactic_hints();
@ -2179,8 +2188,10 @@ std::tuple<expr, expr, level_param_names> elaborator::operator()(expr const & t,
substitution s = p->first.first; substitution s = p->first.first;
name_set univ_params = collect_univ_params(r_v, collect_univ_params(r_t)); name_set univ_params = collect_univ_params(r_v, collect_univ_params(r_t));
buffer<name> new_params; buffer<name> new_params;
expr new_r_t = apply(s, r_t, univ_params, new_params); bool is_value = false;
expr new_r_v = apply(s, r_v, univ_params, new_params); expr new_r_t = apply(s, r_t, univ_params, new_params, is_value);
is_value = true;
expr new_r_v = apply(s, r_v, univ_params, new_params, is_value);
check_sort_assignments(s); check_sort_assignments(s);
instantiate_info(s); instantiate_info(s);
check_used_local_tactic_hints(); check_used_local_tactic_hints();
@ -2255,7 +2266,8 @@ elaborate_result elaborator::elaborate_nested(list<expr> const & ctx, optional<e
substitution new_subst = p->first.first; substitution new_subst = p->first.first;
constraints rcs = p->first.second; constraints rcs = p->first.second;
r = new_subst.instantiate_all(r); r = new_subst.instantiate_all(r);
r = solve_unassigned_mvars(new_subst, r); bool reject_type_is_meta = false;
r = solve_unassigned_mvars(new_subst, r, reject_type_is_meta);
rcs = map(rcs, [&](constraint const & c) { return instantiate_metavars(c, new_subst); }); rcs = map(rcs, [&](constraint const & c) { return instantiate_metavars(c, new_subst); });
instantiate_info(new_subst); instantiate_info(new_subst);
if (report_unassigned) if (report_unassigned)

View file

@ -164,13 +164,13 @@ class elaborator : public coercion_info_manager {
bool try_using(substitution & subst, expr const & mvar, proof_state const & ps, bool try_using(substitution & subst, expr const & mvar, proof_state const & ps,
expr const & pre_tac, tactic const & tac, bool show_failure); expr const & pre_tac, tactic const & tac, bool show_failure);
bool try_using_begin_end(substitution & subst, expr const & mvar, proof_state ps, expr const & pre_tac); bool try_using_begin_end(substitution & subst, expr const & mvar, proof_state ps, expr const & pre_tac);
void solve_unassigned_mvar(substitution & subst, expr mvar, name_set & visited); void solve_unassigned_mvar(substitution & subst, expr mvar, name_set & visited, bool reject_type_is_meta);
expr solve_unassigned_mvars(substitution & subst, expr e, name_set & visited); expr solve_unassigned_mvars(substitution & subst, expr e, name_set & visited, bool reject_type_is_meta);
expr solve_unassigned_mvars(substitution & subst, expr const & e); expr solve_unassigned_mvars(substitution & subst, expr const & e, bool reject_type_is_meta);
bool display_unassigned_mvars(expr const & e, substitution const & s); bool display_unassigned_mvars(expr const & e, substitution const & s);
void check_sort_assignments(substitution const & s); void check_sort_assignments(substitution const & s);
expr apply(substitution & s, expr const & e, name_set & univ_params, buffer<name> & new_params); expr apply(substitution & s, expr const & e, name_set & univ_params, buffer<name> & new_params, bool is_def_value);
std::tuple<expr, level_param_names> apply(substitution & s, expr const & e); std::tuple<expr, level_param_names> apply(substitution & s, expr const & e, bool is_def_value);
elaborate_result elaborate_nested(list<expr> const & ctx, optional<expr> const & expected_type, expr const & e, elaborate_result elaborate_nested(list<expr> const & ctx, optional<expr> const & expected_type, expr const & e,
bool use_tactic_hints, substitution const &, bool report_unassigned); bool use_tactic_hints, substitution const &, bool report_unassigned);

View file

@ -1,22 +1,2 @@
626a.lean:3:42: error: don't know how to synthesize placeholder 626a.lean:3:42: error: failed to synthesize placeholder, type is a unknown (i.e., it is a metavariable) (solution: provide type explicitly)
c : C¹ 626a.lean:8:42: error: failed to synthesize placeholder, type is a unknown (i.e., it is a metavariable) (solution: provide type explicitly)
⊢ ?M_1
626a.lean:3:44: error: don't know how to synthesize placeholder
c : C¹
⊢ Π (a : nat),
?M_1 → ?M_1
626a.lean:3:29: error: failed to add declaration 'foo.foo' to environment, value has metavariables
remark: set 'formatter.hide_full_terms' to false to see the complete term
λ (c : C¹),
nat.rec_on c ?M_2 ?M_3
626a.lean:8:42: error: don't know how to synthesize placeholder
c : C¹
⊢ ?M_1
626a.lean:8:44: error: don't know how to synthesize placeholder
c : C¹
⊢ Π (a : C¹),
?M_1 → ?M_1
626a.lean:8:29: error: failed to add declaration 'boo.foo' to environment, value has metavariables
remark: set 'formatter.hide_full_terms' to false to see the complete term
λ (c : C¹),
nat.rec_on c ?M_2 ?M_3

View file

@ -1,55 +1,5 @@
626c.lean:2:40: error: don't know how to synthesize placeholder 626c.lean:2:40: error: failed to synthesize placeholder, type is a unknown (i.e., it is a metavariable) (solution: provide type explicitly)
c : C⁽ 626c.lean:5:40: error: failed to synthesize placeholder, type is a unknown (i.e., it is a metavariable) (solution: provide type explicitly)
⊢ ?M_1 626c.lean:8:40: error: failed to synthesize placeholder, type is a unknown (i.e., it is a metavariable) (solution: provide type explicitly)
626c.lean:2:42: error: don't know how to synthesize placeholder 626c.lean:11:41: error: failed to synthesize placeholder, type is a unknown (i.e., it is a metavariable) (solution: provide type explicitly)
c : C⁽ 626c.lean:14:42: error: failed to synthesize placeholder, type is a unknown (i.e., it is a metavariable) (solution: provide type explicitly)
⊢ Π (a : C⁽),
?M_1 → ?M_1
626c.lean:2:27: error: failed to add declaration 'foo' to environment, value has metavariables
remark: set 'formatter.hide_full_terms' to false to see the complete term
λ (c : C⁽),
nat.rec_on c ?M_2 ?M_3
626c.lean:5:40: error: don't know how to synthesize placeholder
c : α⁽
⊢ ?M_1
626c.lean:5:42: error: don't know how to synthesize placeholder
c : α⁽
⊢ Π (a : α⁽),
?M_1 → ?M_1
626c.lean:5:27: error: failed to add declaration 'foo' to environment, value has metavariables
remark: set 'formatter.hide_full_terms' to false to see the complete term
λ (c : α⁽),
nat.rec_on c ?M_2 ?M_3
626c.lean:8:40: error: don't know how to synthesize placeholder
c : _⁽
⊢ ?M_1
626c.lean:8:42: error: don't know how to synthesize placeholder
c : _⁽
⊢ Π (a : _⁽),
?M_1 → ?M_1
626c.lean:8:27: error: failed to add declaration 'foo' to environment, value has metavariables
remark: set 'formatter.hide_full_terms' to false to see the complete term
λ (c : _⁽),
nat.rec_on c ?M_2 ?M_3
626c.lean:11:41: error: don't know how to synthesize placeholder
c : C.⁽
⊢ ?M_1
626c.lean:11:43: error: don't know how to synthesize placeholder
c : C.⁽
⊢ Π (a : C.⁽),
?M_1 → ?M_1
626c.lean:11:28: error: failed to add declaration 'foo' to environment, value has metavariables
remark: set 'formatter.hide_full_terms' to false to see the complete term
λ (c : C.⁽),
nat.rec_on c ?M_2 ?M_3
626c.lean:14:42: error: don't know how to synthesize placeholder
c : C⁽C⁽
⊢ ?M_1
626c.lean:14:44: error: don't know how to synthesize placeholder
c : C⁽C⁽
⊢ Π (a : C⁽C⁽),
?M_1 → ?M_1
626c.lean:14:29: error: failed to add declaration 'foo' to environment, value has metavariables
remark: set 'formatter.hide_full_terms' to false to see the complete term
λ (c : C⁽C⁽),
nat.rec_on c ?M_2 ?M_3

12
tests/lean/771.lean Normal file
View file

@ -0,0 +1,12 @@
set_option pp.all true
definition id_1 (n : nat) :=
by exact n
definition id_2 (n : nat) :=
(by exact n : nat)
definition id_3 (n : nat) : nat :=
by exact n
definition id_4 (n : nat) :=
show nat, by exact n

View file

@ -0,0 +1 @@
771.lean:3:3: error: failed to synthesize placeholder, type is a unknown (i.e., it is a metavariable) (solution: provide type explicitly)