示例#1
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;
}
示例#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;
}