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:
parent
6a079fdd2d
commit
5568085ab9
6 changed files with 52 additions and 97 deletions
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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
12
tests/lean/771.lean
Normal 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
|
1
tests/lean/771.lean.expected.out
Normal file
1
tests/lean/771.lean.expected.out
Normal 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)
|
Loading…
Reference in a new issue