bool is_ceqv(type_checker & tc, expr e) { if (has_expr_metavar(e)) return false; name_set to_find; // Define a procedure for removing arguments from to_find. auto visitor_fn = [&](expr const & e, unsigned) { if (is_local(e)) { to_find.erase(mlocal_name(e)); return false; } else if (is_metavar(e)) { return false; } else { return true; } }; environment const & env = tc.env(); bool is_std = is_standard(env); buffer<expr> hypotheses; // arguments that are propositions while (is_pi(e)) { if (!to_find.empty()) { // Support for dependent types. // We may find the instantiation for the previous arguments // by matching the type. for_each(binding_domain(e), visitor_fn); } expr local = mk_local(tc.mk_fresh_name(), binding_domain(e)); if (binding_info(e).is_inst_implicit()) { // If the argument can be instantiated by type class resolution, then // we don't need to find it in the lhs } else if (is_std && tc.is_prop(binding_domain(e)).first) { // If the argument is a proposition, we store it in hypotheses. // We check whether the lhs occurs in hypotheses or not. hypotheses.push_back(binding_domain(e)); } else { to_find.insert(mlocal_name(local)); } e = instantiate(binding_body(e), local); } expr lhs, rhs; if (!is_simp_relation(env, e, lhs, rhs)) return false; // traverse lhs, and remove found variables from to_find for_each(lhs, visitor_fn); if (!to_find.empty()) return false; // basic looping ceq detection: the left-hand-side should not occur in the right-hand-side, // nor it should occur in any of the hypothesis if (occurs(lhs, rhs)) return false; if (std::any_of(hypotheses.begin(), hypotheses.end(), [&](expr const & h) { return occurs(lhs, h); })) return false; return true; }
expr visit_binding(expr e) { expr_kind k = e.kind(); buffer<expr> es; buffer<expr> ls; while (e.kind() == k) { expr d = visit(instantiate_rev(binding_domain(e), ls.size(), ls.data())); expr l = mk_local(m_tc.mk_fresh_name(), binding_name(e), d, binding_info(e)); ls.push_back(l); es.push_back(e); e = binding_body(e); } e = visit(instantiate_rev(e, ls.size(), ls.data())); expr r = abstract_locals(e, ls.size(), ls.data()); while (!ls.empty()) { expr d = mlocal_type(ls.back()); ls.pop_back(); d = abstract_locals(d, ls.size(), ls.data()); r = update_binding(es.back(), d, r); es.pop_back(); } return r; }
expr visit_binding(expr const & b) { expr new_domain = visit(binding_domain(b)); expr l = mk_local(m_tc.mk_fresh_name(), new_domain); expr new_body = abstract(visit(instantiate(binding_body(b), l)), l); return update_binding(b, new_domain, new_body); }
name converter::mk_fresh_name(type_checker & tc) { return tc.mk_fresh_name(); }
optional<expr> mk_hset_instance(type_checker & tc, io_state const & ios, list<expr> const & ctx, expr const & type) { expr trunc_index = mk_app(mk_constant(get_is_trunc_trunc_index_of_nat_name()), mk_constant(get_nat_zero_name())); level lvl = sort_level(tc.ensure_type(type).first); expr is_hset = mk_app(mk_constant(get_is_trunc_name(), {lvl}), trunc_index, type); return mk_class_instance(tc.env(), ios, ctx, tc.mk_fresh_name(), is_hset); }