vm_obj tactic_to_expr_core(vm_obj const & relaxed, vm_obj const & qe, vm_obj const & _s) { tactic_state const & s = to_tactic_state(_s); optional<metavar_decl> g = s.get_main_goal_decl(); if (!g) return mk_no_goals_exception(s); if (!g_elaborate) { return mk_tactic_exception("elaborator is not available", s); } metavar_context mctx = s.mctx(); try { environment env = s.env(); expr r = (*g_elaborate)(env, s.get_options(), mctx, g->get_context(), to_expr(qe), to_bool(relaxed)); r = mctx.instantiate_mvars(r); if (relaxed && has_expr_metavar(r)) { buffer<expr> new_goals; name_set found; for_each(r, [&](expr const & e, unsigned) { if (!has_expr_metavar(e)) return false; if (is_metavar_decl_ref(e) && !found.contains(mlocal_name(e))) { mctx.instantiate_mvars_at_type_of(e); new_goals.push_back(e); found.insert(mlocal_name(e)); } return true; }); list<expr> new_gs = cons(head(s.goals()), to_list(new_goals.begin(), new_goals.end(), tail(s.goals()))); return mk_tactic_success(to_obj(r), set_env_mctx_goals(s, env, mctx, new_gs)); } else { return mk_tactic_success(to_obj(r), set_env_mctx(s, env, mctx)); } } catch (exception & ex) { return mk_tactic_exception(ex, s); } }
optional<expr> has_expr_metavar_strict(expr const & e) { if (!has_expr_metavar(e)) return none_expr(); optional<expr> r; for_each(e, [&](expr const & e, unsigned) { if (r || !has_expr_metavar(e)) return false; if (is_meta(e)) { r = e; return false; } if (is_local(e)) return false; // do not visit type return true; }); return r; }
bool projection_converter::postpone_is_def_eq(expr const & t, expr const & s) { if (has_expr_metavar(t) || has_expr_metavar(s)) { auto it1 = is_projection(t); auto it2 = is_projection(s); if (it1 && it2) { return true; } if (it1 && is_stuck(t, *m_tc)) return true; if (it2 && is_stuck(s, *m_tc)) return true; } return default_converter::postpone_is_def_eq(t, s); }
action_result assert_cc_action(hypothesis_idx hidx) { if (!get_config().m_cc) return action_result::failed(); congruence_closure & cc = get_cc(); if (has_expr_metavar(curr_state().get_hypothesis_decl(hidx).get_type())) return action_result::failed(); cc.add(hidx); // cc.display(); if (cc.is_inconsistent()) { try { app_builder & b = get_app_builder(); expr false_proof = *cc.get_inconsistency_proof(); trace_action("contradiction by congruence closure"); return action_result(b.mk_false_rec(curr_state().get_target(), false_proof)); } catch (app_builder_exception &) { return action_result::failed(); } } else { expr const & target = curr_state().get_target(); name R; expr lhs, rhs; if (is_relation_app(target, R, lhs, rhs) && cc.is_eqv(R, lhs, rhs)) { expr proof = *cc.get_eqv_proof(R, lhs, rhs); trace_action("equivalence by congruence closure"); return action_result(proof); } else if (is_prop(target) && !is_false(target) && cc.proved(target)) { expr proof = *cc.get_proof(target); trace_action("equivalent to true by congruence closure"); return action_result(proof); } else { return action_result::new_branch(); } } }
bool has_idx_metavar(expr const & e) { if (!has_univ_metavar(e) && !has_expr_metavar(e)) return false; bool found = false; for_each(e, [&](expr const & e, unsigned) { if (found) return false; if (!has_univ_metavar(e) && !has_expr_metavar(e)) return false; if (is_idx_metavar(e)) found = true; else if (is_constant(e) && std::any_of(const_levels(e).begin(), const_levels(e).end(), has_idx_metauniv)) found = true; else if (is_sort(e) && has_idx_metauniv(sort_level(e))) found = true; return true; }); return found; }
bool is_ceqv(tmp_type_context & tctx, 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 = tctx.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 = tctx.mk_tmp_local(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 && tctx.is_prop(binding_domain(e))) { // 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; }
bool substitution::occurs_expr_core(name const & m, expr const & e, name_set & visited) const { bool found = false; for_each(e, [&](expr const & e, unsigned) { if (found || !has_expr_metavar(e)) return false; if (is_metavar(e)) { name const & n = mlocal_name(e); if (n == m) found = true; auto s = get_expr(e); if (!s || visited.contains(n)) return false; // do not visit type visited.insert(n); if (s && occurs_expr_core(m, *s, visited)) found = true; return false; // do not visit type } if (is_local(e)) return false; // do not visit type return true; }); return found; }
bool substitution::occurs_expr(name const & m, expr const & e) const { if (!has_expr_metavar(e)) return false; name_set visited; return occurs_expr_core(m, e, visited); }