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, 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());
 }
 virtual optional<expr> expand(expr const & m, extension_context & ctx) const {
     environment const & env = ctx.env();
     check_num_args(env, m);
     expr l     = whnf(macro_arg(m, 0), ctx);
     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, 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));
 }
action_result no_confusion_action(hypothesis_idx hidx) {
    try {
        state & s       = curr_state();
        app_builder & b = get_app_builder();
        hypothesis const & h = s.get_hypothesis_decl(hidx);
        expr type = h.get_type();
        expr lhs, rhs;
        if (!is_eq(type, lhs, rhs))
            return action_result::failed();
        lhs = whnf(lhs);
        rhs = whnf(rhs);
        optional<name> c1 = is_constructor_app(env(), lhs);
        optional<name> c2 = is_constructor_app(env(), rhs);
        if (!c1 || !c2)
            return action_result::failed();
        expr A = whnf(infer_type(lhs));
        expr I = get_app_fn(A);
        if (!is_constant(I) || !inductive::is_inductive_decl(env(), const_name(I)))
            return action_result::failed();
        name nct_name(const_name(I), "no_confusion_type");
        if (!env().find(nct_name))
            return action_result::failed();
        expr target  = s.get_target();
        expr nct     = whnf(b.mk_app(nct_name, target, lhs, rhs));
        if (c1 == c2) {
            if (!is_pi(nct))
                return action_result::failed();
            if (s.has_target_forward_deps(hidx)) {
                // TODO(Leo): we currently do not handle this case.
                // To avoid non-termination we remove the given hypothesis, if there
                // forward dependencies, we would also have to remove them.
                // Remark: this is a low priority refinement since it will not happen
                // very often in practice.
                return action_result::failed();
            }
            unsigned num_params  = *inductive::get_num_params(env(), const_name(I));
            unsigned cnstr_arity = get_arity(env().get(*c1).get_type());
            lean_assert(cnstr_arity >= num_params);
            unsigned num_new_eqs = cnstr_arity - num_params;
            s.push_proof_step(new no_confusion_proof_step_cell(const_name(I), target, h.get_self(), num_new_eqs));
            s.set_target(binding_domain(nct));
            s.del_hypothesis(hidx);
            trace_action("no_confusion");
            return action_result::new_branch();
        } else {
            name nc_name(const_name(I), "no_confusion");
            expr pr = b.mk_app(nc_name, {target, lhs, rhs, h.get_self()});
            trace_action("no_confusion");
            return action_result::solved(pr);
        }
    } catch (app_builder_exception &) {
        return action_result::failed();
    }
}
Example #4
0
/* Infers the type of operations with return types. For unary operators, such as
! and unary minus, the operator is assigned the return type of its child.
For binary operators, the operator is assigned the return type of its
children, only if both children have the same return type.
 */
void infer_type(ast_node root){

  /* Note: post-order traversal, unlike most other traversals */
  ast_node child;
  for (child = root->left_child; child != NULL; child = child->right_sibling){
    infer_type(child);
  }

  /* Only assign a return type to nodes withouth one already */
  if(root->return_type == 0){

    if(is_unary_operator(root)){
      root->return_type = root->left_child->return_type;

    } else if(is_binary_operator(root)){
      /* Check that the types of both children are equal */
      /* Assignment operator is also checked here, since it is a binary operator */
      if(root->left_child->return_type == root->left_child->right_sibling->return_type){
        root->return_type = root->left_child->return_type;
      }
    }
  } else{
  }
}
Example #5
0
		value_type binary_op::infer_type(object_converter converter, value_type) {
			return infer_type(converter);
		}