Пример #1
0
static bool is_recursive_interface(ast_t* sub, ast_t* super, ast_t* isub,
  ast_t* isuper)
{
  if(isuper == NULL)
  {
    assert(isub == NULL);
    return false;
  }

  assert(ast_id(isub) == TK_NOMINAL);
  assert(ast_id(isuper) == TK_NOMINAL);

  return (ast_id(sub) == TK_NOMINAL) && (ast_id(super) == TK_NOMINAL) &&
    is_eqtype(sub, isub) && is_eqtype(super, isuper);
}
Пример #2
0
// Attach the appropriate body (if any) from the given method list to the given
// entity method
static void attach_body_from_list(ast_t* list, ast_t* entity_method)
{
  assert(list != NULL);
  assert(entity_method != NULL);

  void* data = ast_data(entity_method);

  for(ast_t* p = ast_child(list); p != NULL; p = ast_sibling(p))
  {
    void* p_data = ast_data(p);

    if(p_data != NULL && p_data != data && is_eqtype(entity_method, p))
    {
      // p has a valid (and different) body

      if(data != NULL || p_data == BODY_AMBIGUOUS)
      {
        // Multiple possible bodies
        ast_setdata(entity_method, BODY_AMBIGUOUS);
        return;
      }

      // This is the first valid body, use it
      ast_t* old_body = ast_childidx(entity_method, 6);
      assert(ast_id(old_body) == TK_NONE);
      ast_replace(&old_body, ast_childidx(p, 6));
      ast_setdata(entity_method, p_data);
      data = p_data;
    }
  }
}
Пример #3
0
// The subtype is an arrow, the supertype is an arrow.
static bool is_arrow_sub_arrow(ast_t* sub, ast_t* super)
{
  // If the supertype is also a viewpoint and the viewpoint is the same, then
  // we are a subtype if our adapted type is a subtype of the supertype's
  // adapted type.
  AST_GET_CHILDREN(sub, sub_left, sub_right);
  AST_GET_CHILDREN(super, super_left, super_right);

  switch(ast_id(sub_left))
  {
    case TK_THISTYPE:
      switch(ast_id(super_left))
      {
        case TK_THISTYPE:
        case TK_BOXTYPE:
          break;

        default:
          return false;
      }
      break;

    case TK_BOXTYPE:
      if(ast_id(super_left) != TK_BOXTYPE)
        return false;
      break;

    default:
      if(!is_eqtype(sub_left, super_left))
        return false;
      break;
  }

  return is_subtype(sub_right, super_right);
}
Пример #4
0
static bool could_subtype_typearg(ast_t* sub, ast_t* super)
{
  token_id tsub = ast_id(sub);
  token_id tsup = ast_id(super);

  if(tsub == TK_TYPEPARAMREF)
    return could_subtype(sub, super) == MATCHTYPE_ACCEPT;

  if(tsup == TK_TYPEPARAMREF)
    return could_subtype(super, sub) == MATCHTYPE_ACCEPT;

  if((tsub == TK_TUPLETYPE) && (tsup == TK_TUPLETYPE))
  {
    ast_t* sub_child = ast_child(sub);
    ast_t* sup_child = ast_child(super);

    while((sub_child != NULL) && (sup_child != NULL))
    {
      if(!could_subtype_typearg(sub_child, sup_child))
        return false;

      sub_child = ast_sibling(sub_child);
      sup_child = ast_sibling(sup_child);
    }

    if((sub_child != NULL) || (sup_child != NULL))
      return false;

    return true;
  }

  return is_eqtype(sub, super);
}
Пример #5
0
// The subtype is an arrow, the supertype could be anything.
static bool is_arrow_subtype(ast_t* sub, ast_t* super)
{
  switch(ast_id(super))
  {
    case TK_UNIONTYPE:
      // A->B <: (C | D)
      if(is_subtype_union(sub, super))
        return true;
      break;

    case TK_ISECTTYPE:
      // A->B <: (C & D)
      if(is_subtype_isect(sub, super))
        return true;
      break;

    case TK_TYPEPARAMREF:
    {
      // A->B <: C
      ast_t* right = ast_child(sub);

      switch(ast_id(right))
      {
        case TK_THISTYPE:
        case TK_BOXTYPE:
          break;

        default:
          if(is_eqtype(right, super))
          {
            // C->B <: C
            // If we are adapted by the supertype, we are a subtype if our
            // lower bounds is a subtype of super.
            ast_t* lower = viewpoint_lower(sub);
            bool ok = is_subtype(lower, super);
            ast_free_unattached(lower);
            return ok;
          }
          break;
      }
      break;
    }

    case TK_ARROW:
      // A->B <: C->D
      if(is_arrow_sub_arrow(sub, super))
        return true;
      break;

    default: {}
  }

  // Otherwise, we are a subtype if our upper bounds is a subtype of super.
  ast_t* upper = viewpoint_upper(sub);
  bool ok = is_subtype(upper, super);
  ast_free_unattached(upper);
  return ok;
}
Пример #6
0
static matchtype_t could_subtype_arrow(ast_t* sub, ast_t* super)
{
  if(ast_id(super) == TK_ARROW)
  {
    // If we have the same viewpoint, check the right side.
    AST_GET_CHILDREN(sub, sub_left, sub_right);
    AST_GET_CHILDREN(super, super_left, super_right);
    bool check = false;

    switch(ast_id(sub_left))
    {
      case TK_THISTYPE:
        switch(ast_id(super_left))
        {
          case TK_THISTYPE:
          case TK_BOXTYPE:
            check = true;
            break;

          default: {}
        }
        break;

      case TK_BOXTYPE:
        check = ast_id(super_left) == TK_BOXTYPE;
        break;

      default:
        check = is_eqtype(sub_left, super_left);
        break;
    }

    if(check)
      return could_subtype(sub_right, super_right);
  }

  // Check the lower bounds.
  ast_t* lower = viewpoint_lower(sub);
  matchtype_t ok = could_subtype(super, lower);

  if(lower != sub)
    ast_free_unattached(lower);

  return ok;
}
Пример #7
0
Файл: reach.c Проект: DevL/ponyc
static void add_types_to_trait(reachable_method_stack_t** s,
  reachable_types_t* r, reachable_type_t* t)
{
  size_t i = HASHMAP_BEGIN;
  reachable_type_t* t2;

  ast_t* def = (ast_t*)ast_data(t->type);
  bool interface = ast_id(def) == TK_INTERFACE;

  while((t2 = reachable_types_next(r, &i)) != NULL)
  {
    if(ast_id(t2->type) == TK_TUPLETYPE)
      continue;

    ast_t* def2 = (ast_t*)ast_data(t2->type);

    switch(ast_id(def2))
    {
      case TK_INTERFACE:
      {
        // Use the same typeid.
        if(interface && is_eqtype(t->type, t2->type, NULL))
          t->type_id = t2->type_id;
        break;
      }

      case TK_PRIMITIVE:
      case TK_CLASS:
      case TK_ACTOR:
        if(is_subtype(t2->type, t->type, NULL))
        {
          reachable_type_cache_put(&t->subtypes, t2);
          reachable_type_cache_put(&t2->subtypes, t);
          add_methods_to_type(s, t, t2);
        }
        break;

      default: {}
    }
  }
}
Пример #8
0
static void add_types_to_trait(reach_t* r, reach_type_t* t,
  pass_opt_t* opt)
{
  size_t i = HASHMAP_BEGIN;
  reach_type_t* t2;

  ast_t* def = (ast_t*)ast_data(t->ast);
  bool interface = ast_id(def) == TK_INTERFACE;

  while((t2 = reach_types_next(&r->types, &i)) != NULL)
  {
    if(ast_id(t2->ast) != TK_NOMINAL)
      continue;

    ast_t* def2 = (ast_t*)ast_data(t2->ast);

    switch(ast_id(def2))
    {
      case TK_INTERFACE:
      {
        // Use the same typeid.
        if(interface && is_eqtype(t->ast, t2->ast, NULL, opt))
          t->type_id = t2->type_id;
        break;
      }

      case TK_PRIMITIVE:
      case TK_CLASS:
      case TK_ACTOR:
        if(is_subtype(t2->ast, t->ast, NULL, opt))
        {
          reach_type_cache_put(&t->subtypes, t2);
          reach_type_cache_put(&t2->subtypes, t);
          add_methods_to_type(r, t, t2, opt);
        }
        break;

      default: {}
    }
  }
}
Пример #9
0
static bool is_eq_typeargs(ast_t* a, ast_t* b)
{
  assert(ast_id(a) == TK_NOMINAL);
  assert(ast_id(b) == TK_NOMINAL);

  // Check typeargs are the same.
  ast_t* a_arg = ast_child(ast_childidx(a, 2));
  ast_t* b_arg = ast_child(ast_childidx(b, 2));

  while((a_arg != NULL) && (b_arg != NULL))
  {
    if(!is_eqtype(a_arg, b_arg))
      return false;

    a_arg = ast_sibling(a_arg);
    b_arg = ast_sibling(b_arg);
  }

  // Make sure we had the same number of typeargs.
  return (a_arg == NULL) && (b_arg == NULL);
}
Пример #10
0
static bool is_eq_typeargs(ast_t* a, ast_t* b, errorframe_t* errors)
{
  assert(ast_id(a) == TK_NOMINAL);
  assert(ast_id(b) == TK_NOMINAL);

  // Check typeargs are the same.
  ast_t* a_arg = ast_child(ast_childidx(a, 2));
  ast_t* b_arg = ast_child(ast_childidx(b, 2));
  bool ret = true;

  while((a_arg != NULL) && (b_arg != NULL))
  {
    if(!is_eqtype(a_arg, b_arg, errors))
      ret = false;

    a_arg = ast_sibling(a_arg);
    b_arg = ast_sibling(b_arg);
  }

  if(!ret && errors != NULL)
  {
    ast_error_frame(errors, a, "%s has different type arguments than %s",
      ast_print_type(a), ast_print_type(b));
  }

  // Make sure we had the same number of typeargs.
  if((a_arg != NULL) || (b_arg != NULL))
  {
    if(errors != NULL)
    {
      ast_error_frame(errors, a,
        "%s has a different number of type arguments than %s",
        ast_print_type(a), ast_print_type(b));
    }

    ret = false;
  }

  return ret;
}
Пример #11
0
static ast_result_t declared_ffi(pass_opt_t* opt, ast_t* call, ast_t* decl)
{
  assert(call != NULL);
  assert(decl != NULL);
  assert(ast_id(decl) == TK_FFIDECL);

  AST_GET_CHILDREN(call, call_name, call_ret_typeargs, args, named_args,
    call_error);
  AST_GET_CHILDREN(decl, decl_name, decl_ret_typeargs, params, named_params,
    decl_error);

  // Check args vs params
  ast_t* param = ast_child(params);
  ast_t* arg = ast_child(args);

  while((arg != NULL) && (param != NULL) && ast_id(param) != TK_ELLIPSIS)
  {
    ast_t* p_type = ast_childidx(param, 1);

    if(!coerce_literals(&arg, p_type, opt))
      return AST_ERROR;

    ast_t* a_type = ast_type(arg);

    errorframe_t info = NULL;
    if((a_type != NULL) &&
      !void_star_param(p_type, a_type) &&
      !is_subtype(a_type, p_type, &info, opt))
    {
      errorframe_t frame = NULL;
      ast_error_frame(&frame, arg, "argument not a subtype of parameter");
      ast_error_frame(&frame, param, "parameter type: %s",
        ast_print_type(p_type));
      ast_error_frame(&frame, arg, "argument type: %s",
        ast_print_type(a_type));
      errorframe_append(&frame, &info);
      errorframe_report(&frame, opt->check.errors);
      return AST_ERROR;
    }

    arg = ast_sibling(arg);
    param = ast_sibling(param);
  }

  if(arg != NULL && param == NULL)
  {
    ast_error(opt->check.errors, arg, "too many arguments");
    return AST_ERROR;
  }

  if(param != NULL && ast_id(param) != TK_ELLIPSIS)
  {
    ast_error(opt->check.errors, named_args, "too few arguments");
    return AST_ERROR;
  }

  for(; arg != NULL; arg = ast_sibling(arg))
  {
    ast_t* a_type = ast_type(arg);

    if((a_type != NULL) && is_type_literal(a_type))
    {
      ast_error(opt->check.errors, arg,
        "Cannot pass number literals as unchecked FFI arguments");
      return AST_ERROR;
    }
  }

  // Check return types
  ast_t* call_ret_type = ast_child(call_ret_typeargs);
  ast_t* decl_ret_type = ast_child(decl_ret_typeargs);

  errorframe_t info = NULL;
  if((call_ret_type != NULL) &&
    !is_eqtype(call_ret_type, decl_ret_type, &info, opt))
  {
    errorframe_t frame = NULL;
    ast_error_frame(&frame, call_ret_type,
      "call return type does not match declaration");
    errorframe_append(&frame, &info);
    errorframe_report(&frame, opt->check.errors);
    return AST_ERROR;
  }

  // Check partiality
  if((ast_id(decl_error) == TK_NONE) && (ast_id(call_error) != TK_NONE))
  {
    ast_error(opt->check.errors, call_error,
      "call is partial but the declaration is not");
    return AST_ERROR;
  }

  if((ast_id(decl_error) == TK_QUESTION) ||
    (ast_id(call_error) == TK_QUESTION))
  {
    ast_seterror(call);
  }

  // Store the declaration so that codegen can generate a non-variadic
  // signature for the FFI call.
  ast_setdata(call, decl);
  ast_settype(call, decl_ret_type);
  ast_inheritflags(call);
  return AST_OK;
}