fix(kernel,library): make sure macros check relevant arguments when kernel is performing full type checking
This commit is contained in:
parent
72663e8a06
commit
061e26157e
22 changed files with 100 additions and 65 deletions
|
@ -48,7 +48,7 @@ class obtain_macro_cell : public macro_definition_cell {
|
|||
public:
|
||||
obtain_macro_cell(obtain_struct const & s):m_struct(s) {}
|
||||
virtual name get_name() const { return *g_obtain_name; }
|
||||
virtual pair<expr, constraint_seq> get_type(expr const &, extension_context &) const { throw_ex(); }
|
||||
virtual pair<expr, constraint_seq> check_type(expr const &, extension_context &, bool) const { throw_ex(); }
|
||||
virtual optional<expr> expand(expr const &, extension_context &) const { throw_ex(); }
|
||||
virtual void write(serializer & s) const {
|
||||
s << *g_obtain_opcode << m_struct;
|
||||
|
|
|
@ -993,7 +993,7 @@ class structure_instance_macro_cell : public macro_definition_cell {
|
|||
public:
|
||||
structure_instance_macro_cell(list<name> const & fs):m_fields(fs) {}
|
||||
virtual name get_name() const { return *g_structure_instance_name; }
|
||||
virtual pair<expr, constraint_seq> get_type(expr const &, extension_context &) const { throw_se_ex(); }
|
||||
virtual pair<expr, constraint_seq> check_type(expr const &, extension_context &, bool) const { throw_se_ex(); }
|
||||
virtual optional<expr> expand(expr const &, extension_context &) const { throw_se_ex(); }
|
||||
virtual void write(serializer & s) const {
|
||||
s << *g_structure_instance_opcode;
|
||||
|
|
|
@ -373,21 +373,6 @@ expr univ_metavars_to_params(environment const & env, local_decls<level> const &
|
|||
return univ_metavars_to_params_fn(env, lls, s, ps, new_ps)(e);
|
||||
}
|
||||
|
||||
justification mk_type_mismatch_jst(expr const & v, expr const & v_type, expr const & t, expr const & src) {
|
||||
return mk_justification(src, [=](formatter const & fmt, substitution const & subst) {
|
||||
substitution s(subst);
|
||||
format expected_fmt, given_fmt;
|
||||
std::tie(expected_fmt, given_fmt) = pp_until_different(fmt, s.instantiate(t), s.instantiate(v_type));
|
||||
format r("type mismatch at term");
|
||||
r += pp_indent_expr(fmt, s.instantiate(v));
|
||||
r += compose(line(), format("has type"));
|
||||
r += given_fmt;
|
||||
r += compose(line(), format("but is expected to have type"));
|
||||
r += expected_fmt;
|
||||
return r;
|
||||
});
|
||||
}
|
||||
|
||||
std::tuple<expr, level_param_names> parse_local_expr(parser & p, bool relaxed) {
|
||||
expr e = p.parse_expr();
|
||||
list<expr> ctx = p.locals_to_context();
|
||||
|
|
|
@ -88,14 +88,6 @@ bool occurs(level const & u, level const & l);
|
|||
expr univ_metavars_to_params(environment const & env, local_decls<level> const & lls, substitution & s,
|
||||
name_set & ps, buffer<name> & new_ps, expr const & e);
|
||||
|
||||
/** \brief Return a justification for \c v_type being definitionally equal to \c t,
|
||||
<tt> v : v_type</tt>, the expressiong \c src is used to extract position information.
|
||||
*/
|
||||
justification mk_type_mismatch_jst(expr const & v, expr const & v_type, expr const & t, expr const & src);
|
||||
inline justification mk_type_mismatch_jst(expr const & v, expr const & v_type, expr const & t) {
|
||||
return mk_type_mismatch_jst(v, v_type, t, v);
|
||||
}
|
||||
|
||||
/** \brief Auxiliary function for check/eval/find_decl */
|
||||
std::tuple<expr, level_param_names> parse_local_expr(parser & p, bool relaxed = true);
|
||||
|
||||
|
|
|
@ -334,7 +334,7 @@ public:
|
|||
macro_definition_cell():m_rc(0) {}
|
||||
virtual ~macro_definition_cell() {}
|
||||
virtual name get_name() const = 0;
|
||||
virtual pair<expr, constraint_seq> get_type(expr const & m, extension_context & ctx) const = 0;
|
||||
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const = 0;
|
||||
virtual optional<expr> expand(expr const & m, extension_context & ctx) const = 0;
|
||||
virtual optional<expr> expand1(expr const & m, extension_context & ctx) const { return expand(m, ctx); }
|
||||
virtual unsigned trust_level() const;
|
||||
|
@ -361,8 +361,8 @@ public:
|
|||
macro_definition & operator=(macro_definition && s);
|
||||
|
||||
name get_name() const { return m_ptr->get_name(); }
|
||||
pair<expr, constraint_seq> get_type(expr const & m, extension_context & ctx) const {
|
||||
return m_ptr->get_type(m, ctx);
|
||||
pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const {
|
||||
return m_ptr->check_type(m, ctx, infer_only);
|
||||
}
|
||||
optional<expr> expand(expr const & m, extension_context & ctx) const { return m_ptr->expand(m, ctx); }
|
||||
optional<expr> expand1(expr const & m, extension_context & ctx) const { return m_ptr->expand1(m, ctx); }
|
||||
|
|
|
@ -11,11 +11,16 @@ namespace lean {
|
|||
expr extension_context::whnf(expr const & e, constraint_seq & cs) {
|
||||
auto p = whnf(e); cs += p.second; return p.first;
|
||||
}
|
||||
expr extension_context::check_type(expr const & e, constraint_seq & cs, bool infer_only) {
|
||||
auto p = check_type(e, infer_only); cs += p.second; return p.first;
|
||||
}
|
||||
pair<expr, constraint_seq> extension_context::infer(expr const & e) {
|
||||
return infer_type(e);
|
||||
bool infer_only = true;
|
||||
return check_type(e, infer_only);
|
||||
}
|
||||
expr extension_context::infer_type(expr const & e, constraint_seq & cs) {
|
||||
auto p = infer_type(e); cs += p.second; return p.first;
|
||||
bool infer_only = true;
|
||||
auto p = check_type(e, infer_only); cs += p.second; return p.first;
|
||||
}
|
||||
bool extension_context::is_def_eq(expr const & e1, expr const & e2, delayed_justification & j, constraint_seq & cs) {
|
||||
auto p = is_def_eq(e1, e2, j); cs += p.second; return p.first;
|
||||
|
|
|
@ -27,9 +27,10 @@ public:
|
|||
virtual environment const & env() const = 0;
|
||||
virtual pair<expr, constraint_seq> whnf(expr const & e) = 0;
|
||||
virtual pair<bool, constraint_seq> is_def_eq(expr const & e1, expr const & e2, delayed_justification & j) = 0;
|
||||
virtual pair<expr, constraint_seq> infer_type(expr const & e) = 0;
|
||||
virtual pair<expr, constraint_seq> check_type(expr const & e, bool infer_only) = 0;
|
||||
virtual optional<expr> is_stuck(expr const & e) = 0;
|
||||
virtual name mk_fresh_name() = 0;
|
||||
expr check_type(expr const & e, constraint_seq & cs, bool infer_only);
|
||||
expr whnf(expr const & e, constraint_seq & cs);
|
||||
pair<expr, constraint_seq> infer(expr const & e);
|
||||
expr infer_type(expr const & e, constraint_seq & cs);
|
||||
|
|
|
@ -189,7 +189,7 @@ expr type_checker::infer_constant(expr const & e, bool infer_only) {
|
|||
|
||||
pair<expr, constraint_seq> type_checker::infer_macro(expr const & e, bool infer_only) {
|
||||
auto def = macro_def(e);
|
||||
pair<expr, constraint_seq> tcs = def.get_type(e, m_tc_ctx);
|
||||
pair<expr, constraint_seq> tcs = def.check_type(e, m_tc_ctx, infer_only);
|
||||
expr t = tcs.first;
|
||||
constraint_seq cs = tcs.second;
|
||||
if (!infer_only && def.trust_level() >= m_env.trust_lvl()) {
|
||||
|
|
|
@ -79,7 +79,9 @@ class type_checker {
|
|||
virtual pair<bool, constraint_seq> is_def_eq(expr const & e1, expr const & e2, delayed_justification & j) {
|
||||
return m_tc.is_def_eq(e1, e2, j);
|
||||
}
|
||||
virtual pair<expr, constraint_seq> infer_type(expr const & e) { return m_tc.infer_type(e); }
|
||||
virtual pair<expr, constraint_seq> check_type(expr const & e, bool infer_only) {
|
||||
return m_tc.infer_type_core(e, infer_only);
|
||||
}
|
||||
virtual name mk_fresh_name() { return m_tc.m_gen.next(); }
|
||||
virtual optional<expr> is_stuck(expr const & e) { return m_tc.is_stuck(e); }
|
||||
};
|
||||
|
|
|
@ -33,9 +33,9 @@ public:
|
|||
virtual name get_name() const { return get_annotation_name(); }
|
||||
virtual format pp(formatter const &) const { return format(m_name); }
|
||||
virtual void display(std::ostream & out) const { out << m_name; }
|
||||
virtual pair<expr, constraint_seq> get_type(expr const & m, extension_context & ctx) const {
|
||||
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const {
|
||||
check_macro(m);
|
||||
return ctx.infer_type(macro_arg(m, 0));
|
||||
return ctx.check_type(macro_arg(m, 0), infer_only);
|
||||
}
|
||||
virtual optional<expr> expand(expr const & m, extension_context &) const {
|
||||
check_macro(m);
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
virtual name get_name() const { return *g_choice_name; }
|
||||
// Choice expressions must be replaced with metavariables before invoking the type checker.
|
||||
// Choice expressions cannot be exported. They are transient/auxiliary objects.
|
||||
virtual pair<expr, constraint_seq> get_type(expr const &, extension_context &) const { throw_ex(); }
|
||||
virtual pair<expr, constraint_seq> check_type(expr const &, extension_context &, bool) const { throw_ex(); }
|
||||
virtual optional<expr> expand(expr const &, extension_context &) const { throw_ex(); }
|
||||
virtual void write(serializer & s) const {
|
||||
// we should be able to write choice expressions because of notation declarations
|
||||
|
|
|
@ -46,7 +46,7 @@ class equations_macro_cell : public macro_definition_cell {
|
|||
public:
|
||||
equations_macro_cell(unsigned num_fns):m_num_fns(num_fns) {}
|
||||
virtual name get_name() const { return *g_equations_name; }
|
||||
virtual pair<expr, constraint_seq> get_type(expr const &, extension_context &) const { throw_eqs_ex(); }
|
||||
virtual pair<expr, constraint_seq> check_type(expr const &, extension_context &, bool) const { throw_eqs_ex(); }
|
||||
virtual optional<expr> expand(expr const &, extension_context &) const { throw_eqs_ex(); }
|
||||
virtual void write(serializer & s) const { s << *g_equations_opcode << m_num_fns; }
|
||||
unsigned get_num_fns() const { return m_num_fns; }
|
||||
|
@ -54,7 +54,7 @@ public:
|
|||
|
||||
class equation_base_macro_cell : public macro_definition_cell {
|
||||
public:
|
||||
virtual pair<expr, constraint_seq> get_type(expr const &, extension_context &) const {
|
||||
virtual pair<expr, constraint_seq> check_type(expr const &, extension_context &, bool) const {
|
||||
expr dummy = mk_Prop();
|
||||
return mk_pair(dummy, constraint_seq());
|
||||
}
|
||||
|
@ -85,9 +85,9 @@ class decreasing_macro_cell : public macro_definition_cell {
|
|||
public:
|
||||
decreasing_macro_cell() {}
|
||||
virtual name get_name() const { return *g_decreasing_name; }
|
||||
virtual pair<expr, constraint_seq> get_type(expr const & m, extension_context & ctx) const {
|
||||
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const {
|
||||
check_macro(m);
|
||||
return ctx.infer_type(macro_arg(m, 0));
|
||||
return ctx.check_type(macro_arg(m, 0), infer_only);
|
||||
}
|
||||
virtual optional<expr> expand(expr const & m, extension_context &) const {
|
||||
check_macro(m);
|
||||
|
@ -204,8 +204,8 @@ bool is_inaccessible(expr const & e) { return is_annotation(e, *g_inaccessible_n
|
|||
class equations_result_macro_cell : public macro_definition_cell {
|
||||
public:
|
||||
virtual name get_name() const { return *g_equations_result_name; }
|
||||
virtual pair<expr, constraint_seq> get_type(expr const & m, extension_context & ctx) const {
|
||||
return ctx.infer_type(macro_arg(m, 0));
|
||||
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const {
|
||||
return ctx.check_type(macro_arg(m, 0), infer_only);
|
||||
}
|
||||
virtual optional<expr> expand(expr const & m, extension_context &) const {
|
||||
return some_expr(macro_arg(m, 0));
|
||||
|
|
|
@ -32,9 +32,9 @@ class let_value_definition_cell : public macro_definition_cell {
|
|||
public:
|
||||
let_value_definition_cell():m_id(next_let_value_id()) {}
|
||||
virtual name get_name() const { return *g_let_value; }
|
||||
virtual pair<expr, constraint_seq> get_type(expr const & m, extension_context & ctx) const {
|
||||
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const {
|
||||
check_macro(m);
|
||||
return ctx.infer_type(macro_arg(m, 0));
|
||||
return ctx.check_type(macro_arg(m, 0), infer_only);
|
||||
}
|
||||
virtual optional<expr> expand(expr const & m, extension_context &) const {
|
||||
check_macro(m);
|
||||
|
@ -75,9 +75,9 @@ public:
|
|||
let_macro_definition_cell(name const & n):m_var_name(n) {}
|
||||
name const & get_var_name() const { return m_var_name; }
|
||||
virtual name get_name() const { return *g_let; }
|
||||
virtual pair<expr, constraint_seq> get_type(expr const & m, extension_context & ctx) const {
|
||||
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const {
|
||||
check_macro(m);
|
||||
return ctx.infer_type(macro_arg(m, 1));
|
||||
return ctx.check_type(macro_arg(m, 1), infer_only);
|
||||
}
|
||||
virtual optional<expr> expand(expr const & m, extension_context &) const {
|
||||
check_macro(m);
|
||||
|
|
|
@ -84,12 +84,12 @@ public:
|
|||
virtual format pp(formatter const &) const { return format(m_proj_name); }
|
||||
virtual void display(std::ostream & out) const { out << m_proj_name; }
|
||||
|
||||
virtual pair<expr, constraint_seq> get_type(expr const & m, extension_context & ctx) const {
|
||||
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const {
|
||||
check_macro(m);
|
||||
environment const & env = ctx.env();
|
||||
constraint_seq cs;
|
||||
expr s = macro_arg(m, 0);
|
||||
expr s_t = ctx.whnf(ctx.infer_type(s, cs), cs);
|
||||
expr s_t = ctx.whnf(ctx.check_type(s, cs, infer_only), cs);
|
||||
buffer<expr> I_args;
|
||||
expr const & I = get_app_args(s_t, I_args);
|
||||
if (is_constant(I)) {
|
||||
|
|
|
@ -97,8 +97,8 @@ public:
|
|||
return r.first;
|
||||
}
|
||||
|
||||
expr infer_type(expr const & e, extension_context & ctx) const {
|
||||
auto r = ctx.infer_type(e);
|
||||
expr infer_type(expr const & e, extension_context & ctx, bool infer_only) const {
|
||||
auto r = ctx.check_type(e, infer_only);
|
||||
if (r.second)
|
||||
throw_kernel_exception(ctx.env(), "invalid resolve macro, constraints were generated while inferring type", e);
|
||||
return r.first;
|
||||
|
@ -150,13 +150,15 @@ public:
|
|||
return mk_bin_rop(*g_or, *g_false, R.size(), R.data());
|
||||
}
|
||||
|
||||
virtual pair<expr, constraint_seq> get_type(expr const & m, extension_context & ctx) const {
|
||||
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const {
|
||||
environment const & env = ctx.env();
|
||||
check_num_args(env, m);
|
||||
if (!infer_only)
|
||||
infer_type(macro_arg(m, 0), ctx, infer_only);
|
||||
expr l = whnf(macro_arg(m, 0), ctx);
|
||||
expr not_l = whnf(mk_app(*g_not, l), ctx);
|
||||
expr C1 = infer_type(macro_arg(m, 1), ctx);
|
||||
expr C2 = infer_type(macro_arg(m, 2), ctx);
|
||||
expr C1 = infer_type(macro_arg(m, 1), ctx, infer_only);
|
||||
expr C2 = infer_type(macro_arg(m, 2), ctx, infer_only);
|
||||
return mk_pair(mk_resolvent(env, ctx, m, l, not_l, C1, C2), constraint_seq());
|
||||
}
|
||||
|
||||
|
@ -175,8 +177,8 @@ public:
|
|||
expr not_l = whnf(mk_app(*g_not, l), ctx);
|
||||
expr H1 = macro_arg(m, 1);
|
||||
expr H2 = macro_arg(m, 2);
|
||||
expr C1 = infer_type(H1, ctx);
|
||||
expr C2 = infer_type(H2, ctx);
|
||||
expr C1 = infer_type(H1, ctx, true);
|
||||
expr C2 = infer_type(H2, ctx, true);
|
||||
expr R = mk_resolvent(env, ctx, m, l, not_l, C1, C2);
|
||||
return some_expr(mk_or_elim_tree1(l, not_l, C1, H1, C2, H2, R, ctx));
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
return m_value < static_cast<string_macro const &>(d).m_value;
|
||||
}
|
||||
virtual name get_name() const { return *g_string_macro; }
|
||||
virtual pair<expr, constraint_seq> get_type(expr const &, extension_context &) const {
|
||||
virtual pair<expr, constraint_seq> check_type(expr const &, extension_context &, bool) const {
|
||||
return mk_pair(*g_string, constraint_seq());
|
||||
}
|
||||
virtual optional<expr> expand(expr const &, extension_context &) const {
|
||||
|
|
|
@ -79,7 +79,7 @@ class tactic_expr_macro_definition_cell : public macro_definition_cell {
|
|||
public:
|
||||
tactic_expr_macro_definition_cell() {}
|
||||
virtual name get_name() const { return get_tactic_expr_name(); }
|
||||
virtual pair<expr, constraint_seq> get_type(expr const &, extension_context &) const {
|
||||
virtual pair<expr, constraint_seq> check_type(expr const &, extension_context &, bool) const {
|
||||
return mk_pair(get_tactic_expr_type(), constraint_seq());
|
||||
}
|
||||
virtual optional<expr> expand(expr const &, extension_context &) const {
|
||||
|
|
|
@ -205,7 +205,7 @@ static std::string * g_rewrite_reduce_opcode = nullptr;
|
|||
|
||||
class rewrite_core_macro_cell : public macro_definition_cell {
|
||||
public:
|
||||
virtual pair<expr, constraint_seq> get_type(expr const &, extension_context &) const { throw_re_ex(); }
|
||||
virtual pair<expr, constraint_seq> check_type(expr const &, extension_context &, bool) const { throw_re_ex(); }
|
||||
virtual optional<expr> expand(expr const &, extension_context &) const { throw_re_ex(); }
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
|||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include <string>
|
||||
#include "kernel/kernel_exception.h"
|
||||
#include "library/util.h"
|
||||
#include "library/kernel_serializer.h"
|
||||
|
||||
namespace lean {
|
||||
|
@ -34,9 +36,25 @@ class typed_expr_macro_definition_cell : public macro_definition_cell {
|
|||
}
|
||||
public:
|
||||
virtual name get_name() const { return get_typed_expr_name(); }
|
||||
virtual pair<expr, constraint_seq> get_type(expr const & m, extension_context & ctx) const {
|
||||
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const {
|
||||
constraint_seq cseq;
|
||||
check_macro(m);
|
||||
return ctx.infer_type(macro_arg(m, 0));
|
||||
expr given_type = macro_arg(m, 0);
|
||||
if (!infer_only) {
|
||||
cseq += ctx.check_type(given_type, infer_only).second;
|
||||
auto p = ctx.check_type(macro_arg(m, 1), infer_only);
|
||||
expr inferred_type = p.first;
|
||||
cseq += p.second;
|
||||
justification jst = mk_type_mismatch_jst(macro_arg(m, 1), inferred_type, given_type, m);
|
||||
as_delayed_justification djst(jst);
|
||||
if (!ctx.is_def_eq(inferred_type, given_type, djst, cseq)) {
|
||||
throw_kernel_exception(ctx.env(), m,
|
||||
[=](formatter const & fmt) {
|
||||
return pp_type_mismatch(fmt, macro_arg(m, 1), inferred_type, given_type);
|
||||
});
|
||||
}
|
||||
}
|
||||
return mk_pair(given_type, cseq);
|
||||
}
|
||||
virtual optional<expr> expand(expr const & m, extension_context &) const {
|
||||
check_macro(m);
|
||||
|
|
|
@ -6,6 +6,7 @@ Author: Leonardo de Moura
|
|||
*/
|
||||
#include "kernel/find_fn.h"
|
||||
#include "kernel/instantiate.h"
|
||||
#include "kernel/error_msgs.h"
|
||||
#include "kernel/abstract.h"
|
||||
#include "kernel/type_checker.h"
|
||||
#include "kernel/metavar.h"
|
||||
|
@ -655,4 +656,23 @@ void check_term(environment const & env, expr const & e) {
|
|||
expr tmp = unfold_untrusted_macros(env, e);
|
||||
type_checker(env).check_ignore_undefined_universes(tmp);
|
||||
}
|
||||
|
||||
format pp_type_mismatch(formatter const & fmt, expr const & v, expr const & v_type, expr const & t) {
|
||||
format expected_fmt, given_fmt;
|
||||
std::tie(expected_fmt, given_fmt) = pp_until_different(fmt, t, v_type);
|
||||
format r("type mismatch at term");
|
||||
r += pp_indent_expr(fmt, v);
|
||||
r += compose(line(), format("has type"));
|
||||
r += given_fmt;
|
||||
r += compose(line(), format("but is expected to have type"));
|
||||
r += expected_fmt;
|
||||
return r;
|
||||
}
|
||||
|
||||
justification mk_type_mismatch_jst(expr const & v, expr const & v_type, expr const & t, expr const & src) {
|
||||
return mk_justification(src, [=](formatter const & fmt, substitution const & subst) {
|
||||
substitution s(subst);
|
||||
return pp_type_mismatch(fmt, s.instantiate(v), s.instantiate(v_type), s.instantiate(t));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -201,6 +201,15 @@ constraint instantiate_metavars(constraint const & c, substitution & s);
|
|||
void check_term(type_checker & tc, expr const & e);
|
||||
void check_term(environment const & env, expr const & e);
|
||||
|
||||
/** \brief Return a justification for \c v_type being definitionally equal to \c t,
|
||||
<tt> v : v_type</tt>, the expressiong \c src is used to extract position information.
|
||||
*/
|
||||
format pp_type_mismatch(formatter const & fmt, expr const & v, expr const & v_type, expr const & t);
|
||||
justification mk_type_mismatch_jst(expr const & v, expr const & v_type, expr const & t, expr const & src);
|
||||
inline justification mk_type_mismatch_jst(expr const & v, expr const & v_type, expr const & t) {
|
||||
return mk_type_mismatch_jst(v, v_type, t, v);
|
||||
}
|
||||
|
||||
void initialize_library_util();
|
||||
void finalize_library_util();
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ namespace finset
|
|||
| [] := (λ a, iff.rfl)
|
||||
| (x :: xs) :=
|
||||
take y,
|
||||
assert ih : xs ~ norep xs, from eqv_norep xs,
|
||||
show y ∈ x :: xs ↔ y ∈ if x ∈ xs then norep xs else x :: norep xs,
|
||||
begin
|
||||
apply (@by_cases (x ∈ xs)),
|
||||
|
@ -35,19 +36,19 @@ namespace finset
|
|||
intro xin, rewrite (if_pos xin),
|
||||
apply iff.intro,
|
||||
{intro yinxxs, apply (or.elim (iff.mp !mem_cons_iff yinxxs)),
|
||||
intro yeqx, rewrite -yeqx at xin, exact (iff.mp (eqv_norep xs y) xin),
|
||||
intro yeqxs, exact (iff.mp (eqv_norep xs y) yeqxs)},
|
||||
{intro yinnrep, show y ∈ x::xs, from or.inr (iff.mp' (eqv_norep xs y) yinnrep)}
|
||||
intro yeqx, rewrite -yeqx at xin, exact (iff.mp (ih y) xin),
|
||||
intro yeqxs, exact (iff.mp (ih y) yeqxs)},
|
||||
{intro yinnrep, show y ∈ x::xs, from or.inr (iff.mp' (ih y) yinnrep)}
|
||||
end,
|
||||
begin
|
||||
intro xnin, rewrite (if_neg xnin),
|
||||
apply iff.intro,
|
||||
{intro yinxxs, apply (or.elim (iff.mp !mem_cons_iff yinxxs)),
|
||||
intro yeqx, rewrite yeqx, apply mem_cons,
|
||||
intro yinxs, show y ∈ x:: norep xs, from or.inr (iff.mp (eqv_norep xs y) yinxs)},
|
||||
intro yinxs, show y ∈ x:: norep xs, from or.inr (iff.mp (ih y) yinxs)},
|
||||
{intro yinxnrep, apply (or.elim (iff.mp !mem_cons_iff yinxnrep)),
|
||||
intro yeqx, rewrite yeqx, apply mem_cons,
|
||||
intro yinrep, show y ∈ x::xs, from or.inr (iff.mp' (eqv_norep xs y) yinrep)}
|
||||
intro yinrep, show y ∈ x::xs, from or.inr (iff.mp' (ih y) yinrep)}
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue