Пример #1
0
static bool method_call(pass_opt_t* opt, ast_t* ast)
{
  if(!method_application(opt, ast, false))
    return false;

  AST_GET_CHILDREN(ast, positional, namedargs, lhs);
  ast_t* type = ast_type(lhs);

  if(is_typecheck_error(type))
    return false;

  AST_GET_CHILDREN(type, cap, typeparams, params, result);
  ast_settype(ast, result);
  ast_inheritflags(ast);

  switch(ast_id(lhs))
  {
    case TK_NEWBEREF:
    case TK_BEREF:
      ast_setsend(ast);
      return true;

    case TK_NEWREF:
    case TK_FUNREF:
      ast_setmightsend(ast);
      return true;

    default: {}
  }

  assert(0);
  return false;
}
Пример #2
0
static int check_body_send(ast_t* ast, bool in_final)
{
  if(ast_checkflag(ast, AST_FLAG_RECURSE_1))
    return FINAL_RECURSE;

  if(ast_cansend(ast))
    return FINAL_CAN_SEND;

  if(!ast_mightsend(ast))
    return FINAL_NO_SEND;

  ast_setflag(ast, AST_FLAG_RECURSE_1);

  int r = check_expr_send(ast, in_final);

  if(r == FINAL_NO_SEND)
  {
    // Mark the body as no send.
    ast_clearmightsend(ast);
  } else if((r & FINAL_CAN_SEND) != 0) {
    // Mark the body as can send.
    ast_setsend(ast);
  }

  ast_clearflag(ast, AST_FLAG_RECURSE_1);
  return r;
}
Пример #3
0
bool verify_behaviour_call(pass_opt_t* opt, ast_t* ast)
{
  (void)opt;
  pony_assert((ast_id(ast) == TK_BEREF) || (ast_id(ast) == TK_BECHAIN) ||
    (ast_id(ast) == TK_NEWBEREF));

  ast_inheritflags(ast);
  ast_setsend(ast);

  return true;
}
Пример #4
0
static int check_call_send(ast_t* ast, bool in_final)
{
  AST_GET_CHILDREN(ast, positional, named, question, lhs);
  AST_GET_CHILDREN(lhs, receiver, method);

  switch(ast_id(receiver))
  {
    case TK_NEWREF:
    case TK_FUNREF:
    case TK_FUNCHAIN:
      // Qualified. Get the real receiver.
      receiver = ast_child(receiver);
      method = ast_sibling(receiver);
      break;

    default: {}
  }

  ast_t* type = ast_type(receiver);

  // If we don't know the final type, we can't be certain of what all
  // implementations of the method do. Leave it as might send.
  if(!is_known(type))
    return FINAL_CAN_SEND;

  ast_t* def = receiver_def(type);
  pony_assert(def != NULL);

  const char* method_name = ast_name(method);
  ast_t* fun = ast_get(def, method_name, NULL);
  pony_assert(fun != NULL);

  AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, can_error, body);
  int r = check_body_send(body, false);

  if(r == FINAL_NO_SEND)
  {
    // Mark the call as no send.
    ast_clearmightsend(ast);
  } else if(in_final && (r == FINAL_RECURSE)) {
    // If we're in the finaliser, which can't recurse, we treat a recurse as
    // a no send.
    ast_clearmightsend(ast);
  } else if((r & FINAL_CAN_SEND) != 0) {
    // Mark the call as can send.
    ast_setsend(ast);
  }

  return r;
}
Пример #5
0
bool expr_try(pass_opt_t* opt, ast_t* ast)
{
    AST_GET_CHILDREN(ast, body, else_clause, then_clause);

    // It has to be possible for the left side to result in an error.
    if((ast_id(ast) == TK_TRY) && !ast_canerror(body))
    {
        ast_error(body, "try expression never results in an error");
        return false;
    }

    ast_t* body_type = ast_type(body);
    ast_t* else_type = ast_type(else_clause);
    ast_t* then_type = ast_type(then_clause);

    if(is_typecheck_error(body_type) ||
            is_typecheck_error(else_type) ||
            is_typecheck_error(then_type))
        return false;

    ast_t* type = NULL;

    if(!is_control_type(body_type))
        type = control_type_add_branch(type, body);

    if(!is_control_type(else_type))
        type = control_type_add_branch(type, else_clause);

    if(type == NULL)
    {
        if(ast_sibling(ast) != NULL)
        {
            ast_error(ast_sibling(ast), "unreachable code");
            return false;
        }

        type = ast_from(ast, TK_TRY);
    }

    // The then clause does not affect the type of the expression.
    if(is_control_type(then_type))
    {
        ast_error(then_clause, "then clause always terminates the function");
        return false;
    }

    if(is_type_literal(then_type))
    {
        ast_error(then_clause, "Cannot infer type of unused literal");
        return false;
    }

    ast_settype(ast, type);

    // Doesn't inherit error from the body.
    if(ast_canerror(else_clause) || ast_canerror(then_clause))
        ast_seterror(ast);

    if(ast_cansend(body) || ast_cansend(else_clause) || ast_cansend(then_clause))
        ast_setsend(ast);

    if(ast_mightsend(body) || ast_mightsend(else_clause) ||
            ast_mightsend(then_clause))
        ast_setmightsend(ast);

    literal_unify_control(ast, opt);

    // Push the symbol status from the then clause to our parent scope.
    ast_inheritstatus(ast_parent(ast), then_clause);
    return true;
}