Fix type checker and elaborator for let expressions. Fix get_coercions (we need to pass the context). Fix pretty printer for def_type_mismatch_exception.
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
2459c4ae7c
commit
8840b37258
8 changed files with 89 additions and 13 deletions
|
@ -262,7 +262,7 @@ class elaborator::imp {
|
||||||
if (!has_metavar(expected) && !has_metavar(given)) {
|
if (!has_metavar(expected) && !has_metavar(given)) {
|
||||||
if (is_convertible(expected, given, ctx)) {
|
if (is_convertible(expected, given, ctx)) {
|
||||||
// compatible
|
// compatible
|
||||||
} else if (m_frontend.get_coercion(given, expected)) {
|
} else if (m_frontend.get_coercion(given, expected, ctx)) {
|
||||||
// compatible if using coercion
|
// compatible if using coercion
|
||||||
num_coercions++;
|
num_coercions++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -381,7 +381,7 @@ class elaborator::imp {
|
||||||
m_constraints.push_back(constraint(expected, given, ctx, r));
|
m_constraints.push_back(constraint(expected, given, ctx, r));
|
||||||
} else {
|
} else {
|
||||||
if (!is_convertible(expected, given, ctx)) {
|
if (!is_convertible(expected, given, ctx)) {
|
||||||
expr coercion = m_frontend.get_coercion(given, expected);
|
expr coercion = m_frontend.get_coercion(given, expected, ctx);
|
||||||
if (coercion) {
|
if (coercion) {
|
||||||
modified = true;
|
modified = true;
|
||||||
args[i] = mk_app(coercion, args[i]);
|
args[i] = mk_app(coercion, args[i]);
|
||||||
|
@ -437,7 +437,7 @@ class elaborator::imp {
|
||||||
m_constraints.push_back(constraint(expected, given, ctx, r));
|
m_constraints.push_back(constraint(expected, given, ctx, r));
|
||||||
} else {
|
} else {
|
||||||
if (!is_convertible(expected, given, ctx)) {
|
if (!is_convertible(expected, given, ctx)) {
|
||||||
expr coercion = m_frontend.get_coercion(given, expected);
|
expr coercion = m_frontend.get_coercion(given, expected, ctx);
|
||||||
if (coercion) {
|
if (coercion) {
|
||||||
v_p.first = mk_app(coercion, v_p.first);
|
v_p.first = mk_app(coercion, v_p.first);
|
||||||
} else {
|
} else {
|
||||||
|
@ -447,7 +447,7 @@ class elaborator::imp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto b_p = process(let_body(e), extend(ctx, let_name(e), t_p.first ? t_p.first : v_p.second, v_p.first));
|
auto b_p = process(let_body(e), extend(ctx, let_name(e), t_p.first ? t_p.first : v_p.second, v_p.first));
|
||||||
expr t = lower_free_vars_mmv(b_p.second, 1, 1);
|
expr t = instantiate_free_var_mmv(b_p.second, 0, v_p.first);
|
||||||
expr new_e = update_let(e, t_p.first, v_p.first, b_p.first);
|
expr new_e = update_let(e, t_p.first, v_p.first, b_p.first);
|
||||||
add_trace(e, new_e);
|
add_trace(e, new_e);
|
||||||
return expr_pair(new_e, t);
|
return expr_pair(new_e, t);
|
||||||
|
|
|
@ -324,9 +324,9 @@ struct frontend::imp {
|
||||||
return expr();
|
return expr();
|
||||||
}
|
}
|
||||||
|
|
||||||
expr get_coercion(expr const & given_type, expr const & expected_type) {
|
expr get_coercion(expr const & given_type, expr const & expected_type, context const & ctx) {
|
||||||
expr norm_given_type = m_env.normalize(given_type);
|
expr norm_given_type = m_env.normalize(given_type, ctx);
|
||||||
expr norm_expected_type = m_env.normalize(expected_type);
|
expr norm_expected_type = m_env.normalize(expected_type, ctx);
|
||||||
return get_coercion_core(norm_given_type, norm_expected_type);
|
return get_coercion_core(norm_given_type, norm_expected_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,7 +414,9 @@ std::vector<bool> const & frontend::get_implicit_arguments(name const & n) const
|
||||||
name const & frontend::get_explicit_version(name const & n) const { return m_imp->get_explicit_version(n); }
|
name const & frontend::get_explicit_version(name const & n) const { return m_imp->get_explicit_version(n); }
|
||||||
|
|
||||||
void frontend::add_coercion(expr const & f) { m_imp->add_coercion(f); }
|
void frontend::add_coercion(expr const & f) { m_imp->add_coercion(f); }
|
||||||
expr frontend::get_coercion(expr const & given_type, expr const & expected_type) const { return m_imp->get_coercion(given_type, expected_type); }
|
expr frontend::get_coercion(expr const & given_type, expr const & expected_type, context const & ctx) const {
|
||||||
|
return m_imp->get_coercion(given_type, expected_type, ctx);
|
||||||
|
}
|
||||||
bool frontend::is_coercion(expr const & f) const { return m_imp->is_coercion(f); }
|
bool frontend::is_coercion(expr const & f) const { return m_imp->is_coercion(f); }
|
||||||
|
|
||||||
state const & frontend::get_state() const { return m_imp->m_state; }
|
state const & frontend::get_state() const { return m_imp->m_state; }
|
||||||
|
|
|
@ -168,7 +168,7 @@ public:
|
||||||
Return the null expression if there is no coercion from \c given_type to
|
Return the null expression if there is no coercion from \c given_type to
|
||||||
\c expected_type.
|
\c expected_type.
|
||||||
*/
|
*/
|
||||||
expr get_coercion(expr const & given_type, expr const & expected_type) const;
|
expr get_coercion(expr const & given_type, expr const & expected_type, context const & ctx) const;
|
||||||
/**
|
/**
|
||||||
\brief Return true iff the given expression is a coercion. That is, it was added using
|
\brief Return true iff the given expression is a coercion. That is, it was added using
|
||||||
\c add_coercion.
|
\c add_coercion.
|
||||||
|
|
|
@ -175,6 +175,7 @@ public:
|
||||||
expr const & get_type() const { return m_type; }
|
expr const & get_type() const { return m_type; }
|
||||||
expr const & get_value() const { return m_value; }
|
expr const & get_value() const { return m_value; }
|
||||||
expr const & get_value_type() const { return m_value_type; }
|
expr const & get_value_type() const { return m_value_type; }
|
||||||
|
virtual expr const & get_main_expr() const { return m_value; }
|
||||||
virtual char const * what() const noexcept { return "definition type mismatch"; }
|
virtual char const * what() const noexcept { return "definition type mismatch"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -140,7 +140,8 @@ public:
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
cache::mk_scope sc(m_cache);
|
cache::mk_scope sc(m_cache);
|
||||||
r = lower_free_vars(infer_type(let_body(e), extend(ctx, let_name(e), lt, let_value(e))), 1);
|
expr t = infer_type(let_body(e), extend(ctx, let_name(e), lt, let_value(e)));
|
||||||
|
r = instantiate(t, let_value(e));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,14 +88,15 @@ format pp(formatter const & fmt, type_expected_exception const & ex, options con
|
||||||
}
|
}
|
||||||
|
|
||||||
format pp(formatter const & fmt, def_type_mismatch_exception const & ex, options const & opts) {
|
format pp(formatter const & fmt, def_type_mismatch_exception const & ex, options const & opts) {
|
||||||
unsigned indent = get_pp_indent(opts);
|
unsigned indent = get_pp_indent(opts);
|
||||||
|
context const & ctx = ex.get_context();
|
||||||
format r;
|
format r;
|
||||||
r += format("type mismatch at definition '");
|
r += format("type mismatch at definition '");
|
||||||
r += format(ex.get_name());
|
r += format(ex.get_name());
|
||||||
r += format("', expected type");
|
r += format("', expected type");
|
||||||
r += nest(indent, compose(line(), fmt(ex.get_type(), opts)));
|
r += nest(indent, compose(line(), fmt(ctx, ex.get_type(), false, opts)));
|
||||||
r += compose(line(), format("Given type:"));
|
r += compose(line(), format("Given type:"));
|
||||||
r += nest(indent, compose(line(), fmt(ex.get_value_type(), opts)));
|
r += nest(indent, compose(line(), fmt(ctx, ex.get_value_type(), false, opts)));
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
51
tests/lean/let4.lean
Normal file
51
tests/lean/let4.lean
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
|
||||||
|
Show
|
||||||
|
let b := true,
|
||||||
|
a : Int := b
|
||||||
|
in a
|
||||||
|
|
||||||
|
Variable vector : Type -> Nat -> Type
|
||||||
|
Variable const {A : Type} (n : Nat) (a : A) : vector A n
|
||||||
|
|
||||||
|
Check
|
||||||
|
let a := 10,
|
||||||
|
v1 := const a true,
|
||||||
|
v2 := v1
|
||||||
|
in v2
|
||||||
|
|
||||||
|
Show
|
||||||
|
let a := 10,
|
||||||
|
v1 : vector Bool a := const a true,
|
||||||
|
v2 : vector Bool a := v1
|
||||||
|
in v2
|
||||||
|
|
||||||
|
Check
|
||||||
|
let a := 10,
|
||||||
|
v1 : vector Bool a := const a true,
|
||||||
|
v2 : vector Bool a := v1
|
||||||
|
in v2
|
||||||
|
|
||||||
|
Check
|
||||||
|
let a := 10,
|
||||||
|
v1 : vector Bool a := const a true,
|
||||||
|
v2 : vector Int a := v1
|
||||||
|
in v2
|
||||||
|
|
||||||
|
Variable foo : (vector Bool 10) -> (vector Int 10)
|
||||||
|
Coercion foo
|
||||||
|
|
||||||
|
Check
|
||||||
|
let a := 10,
|
||||||
|
v1 : vector Bool a := const a true,
|
||||||
|
v2 : vector Int a := v1
|
||||||
|
in v2
|
||||||
|
|
||||||
|
Set pp::coercion true
|
||||||
|
|
||||||
|
Show
|
||||||
|
let a := 10,
|
||||||
|
v1 : vector Bool a := const a true,
|
||||||
|
v2 : vector Int a := v1
|
||||||
|
in v2
|
||||||
|
|
||||||
|
|
20
tests/lean/let4.lean.expected.out
Normal file
20
tests/lean/let4.lean.expected.out
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
Set: pp::colors
|
||||||
|
Set: pp::unicode
|
||||||
|
Error (line: 4, pos: 15) type mismatch at definition 'a', expected type
|
||||||
|
ℤ
|
||||||
|
Given type:
|
||||||
|
Bool
|
||||||
|
Assumed: vector
|
||||||
|
Assumed: const
|
||||||
|
vector Bool 10
|
||||||
|
let a := 10, v1 : vector Bool a := const a ⊤, v2 : vector Bool a := v1 in v2
|
||||||
|
vector Bool 10
|
||||||
|
Error (line: 31, pos: 26) type mismatch at definition 'v2', expected type
|
||||||
|
vector ℤ a
|
||||||
|
Given type:
|
||||||
|
vector Bool a
|
||||||
|
Assumed: foo
|
||||||
|
Coercion foo
|
||||||
|
vector ℤ 10
|
||||||
|
Set: lean::pp::coercion
|
||||||
|
let a := 10, v1 : vector Bool a := const a ⊤, v2 : vector ℤ a := foo v1 in v2
|
Loading…
Reference in a new issue