Ejemplo n.º 1
0
static bool check_receiver_cap(pass_opt_t* opt, ast_t* ast, bool incomplete)
{
  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);

  // Check receiver cap.
  ast_t* receiver = ast_child(lhs);

  // Dig through function qualification.
  if(ast_id(receiver) == TK_FUNREF || ast_id(receiver) == TK_FUNAPP)
    receiver = ast_child(receiver);

  // Receiver type, alias of receiver type, and target type.
  ast_t* r_type = ast_type(receiver);

  if(is_typecheck_error(r_type))
    return false;

  ast_t* t_type = set_cap_and_ephemeral(r_type, ast_id(cap), TK_NONE);
  ast_t* a_type;

  // If we can recover the receiver, we don't alias it here.
  bool can_recover = auto_recover_call(ast, r_type, positional, result);
  bool cap_recover = false;

  switch(ast_id(cap))
  {
    case TK_ISO:
    case TK_TRN:
    case TK_VAL:
    case TK_TAG:
      break;

    case TK_REF:
    case TK_BOX:
      cap_recover = true;
      break;

    default:
      assert(0);
  }

  if(can_recover && cap_recover)
    a_type = r_type;
  else
    a_type = alias(r_type);

  if(incomplete && (ast_id(receiver) == TK_THIS))
  {
    // If 'this' is incomplete and the arg is 'this', change the type to tag.
    ast_t* tag_type = set_cap_and_ephemeral(a_type, TK_TAG, TK_NONE);

    if(a_type != r_type)
      ast_free_unattached(a_type);

    a_type = tag_type;
  } else {
    incomplete = false;
  }

  errorframe_t info = NULL;
  bool ok = is_subtype(a_type, t_type, &info, opt);

  if(!ok)
  {
    errorframe_t frame = NULL;

    ast_error_frame(&frame, ast,
      "receiver type is not a subtype of target type");
    ast_error_frame(&frame, receiver,
      "receiver type: %s", ast_print_type(a_type));
    ast_error_frame(&frame, cap,
      "target type: %s", ast_print_type(t_type));

    if(!can_recover && cap_recover && is_subtype(r_type, t_type, NULL, opt))
    {
      ast_error_frame(&frame, ast,
        "this would be possible if the arguments and return value "
        "were all sendable");
    }

    if(incomplete && is_subtype(r_type, t_type, NULL, opt))
    {
      ast_error_frame(&frame, ast,
        "this would be possible if all the fields of 'this' were assigned to "
        "at this point");
    }

    errorframe_append(&frame, &info);
    errorframe_report(&frame, opt->check.errors);
  }

  if(a_type != r_type)
    ast_free_unattached(a_type);

  ast_free_unattached(r_type);
  ast_free_unattached(t_type);
  return ok;
}
Ejemplo n.º 2
0
static bool check_receiver_cap(pass_opt_t* opt, ast_t* ast, bool* recovered)
{
  AST_GET_CHILDREN(ast, positional, namedargs, question, lhs);

  ast_t* type = ast_type(lhs);

  if(is_typecheck_error(type))
    return false;

  AST_GET_CHILDREN(type, cap, typeparams, params, result);

  // Receiver type, alias of receiver type, and target type.
  ast_t* r_type = method_receiver_type(lhs);

  if(is_typecheck_error(r_type))
    return false;

  ast_t* t_type = set_cap_and_ephemeral(r_type, ast_id(cap), TK_NONE);
  ast_t* a_type;

  // If we can recover the receiver, we don't alias it here.
  bool can_recover = auto_recover_call(lhs, r_type, positional, result);
  bool cap_recover = false;

  switch(ast_id(cap))
  {
    case TK_ISO:
    case TK_TRN:
    case TK_VAL:
    case TK_TAG:
      break;

    case TK_REF:
    case TK_BOX:
      cap_recover = true;
      break;

    default:
      pony_assert(0);
  }

  if(can_recover && cap_recover)
  {
    a_type = r_type;
    if(recovered != NULL)
      *recovered = true;
  }
  else
  {
    a_type = alias(r_type);
    if(recovered != NULL)
      *recovered = false;
  }

  errorframe_t info = NULL;
  bool ok = is_subtype(a_type, t_type, &info, opt);

  if(!ok)
  {
    errorframe_t frame = NULL;

    ast_error_frame(&frame, ast,
      "receiver type is not a subtype of target type");
    ast_error_frame(&frame, ast_child(lhs),
      "receiver type: %s", ast_print_type(a_type));
    ast_error_frame(&frame, cap,
      "target type: %s", ast_print_type(t_type));
    errorframe_append(&frame, &info);

    if(ast_checkflag(ast_type(method_receiver(lhs)), AST_FLAG_INCOMPLETE))
      ast_error_frame(&frame, method_receiver(lhs),
        "this might be possible if all fields were already defined");

    if(!can_recover && cap_recover && is_subtype(r_type, t_type, NULL, opt))
    {
      ast_error_frame(&frame, ast,
        "this would be possible if the arguments and return value "
        "were all sendable");
    }

    errorframe_report(&frame, opt->check.errors);
  }

  if(a_type != r_type)
    ast_free_unattached(a_type);

  ast_free_unattached(r_type);
  ast_free_unattached(t_type);
  return ok;
}