Exemple #1
0
static matchtype_t is_tuple_match_tuple(ast_t* operand, ast_t* pattern)
{
  // Must be a pairwise match.
  if(ast_childcount(operand) != ast_childcount(pattern))
    return MATCHTYPE_REJECT;

  ast_t* operand_child = ast_child(operand);
  ast_t* pattern_child = ast_child(pattern);
  matchtype_t ok = MATCHTYPE_ACCEPT;

  while(operand_child != NULL)
  {
    switch(is_matchtype(operand_child, pattern_child))
    {
      case MATCHTYPE_ACCEPT:
        break;

      case MATCHTYPE_REJECT:
        ok = MATCHTYPE_REJECT;
        break;

      case MATCHTYPE_DENY:
        return MATCHTYPE_DENY;
    }

    operand_child = ast_sibling(operand_child);
    pattern_child = ast_sibling(pattern_child);
  }

  return ok;
}
Exemple #2
0
int subtype_kind_overlap(reach_type_t* left, reach_type_t* right)
{
  int subtypes = SUBTYPE_KIND_NONE;

  size_t i = HASHMAP_BEGIN;
  reach_type_t* sub_left;

  while((sub_left = reach_type_cache_next(&left->subtypes, &i)) != NULL)
  {
    if(!sub_left->can_be_boxed)
    {
      subtypes |= SUBTYPE_KIND_UNBOXED;
      if(subtypes == SUBTYPE_KIND_ALL)
        return subtypes;

      continue;
    }

    if(sub_left->underlying != TK_TUPLETYPE)
    {
      reach_type_t k;
      k.name = sub_left->name;
      size_t j = HASHMAP_UNKNOWN;
      reach_type_t* sub_right = reach_type_cache_get(&right->subtypes, &k, &j);

      if(sub_right != NULL)
      {
        pony_assert(sub_left == sub_right);

        if(sub_left->underlying == TK_PRIMITIVE)
          subtypes |= SUBTYPE_KIND_NUMERIC;

        if(subtypes == SUBTYPE_KIND_ALL)
          return subtypes;
      }
    } else if((subtypes & SUBTYPE_KIND_TUPLE) == 0) {
      size_t cardinality = ast_childcount(sub_left->ast_cap);
      size_t j = HASHMAP_UNKNOWN;
      reach_type_t* sub_right;

      while((sub_right = reach_type_cache_next(&right->subtypes, &j)) != NULL)
      {
        if((sub_right->underlying == TK_TUPLETYPE) &&
          (ast_childcount(sub_right->ast_cap) == cardinality))
        {
          subtypes |= SUBTYPE_KIND_TUPLE;

          if(subtypes == SUBTYPE_KIND_ALL)
            return subtypes;

          break;
        }
      }
    }
  }

  return subtypes;
}
Exemple #3
0
bool reify_defaults(ast_t* typeparams, ast_t* typeargs, bool errors,
  pass_opt_t* opt)
{
  assert(
    (ast_id(typeparams) == TK_TYPEPARAMS) ||
    (ast_id(typeparams) == TK_NONE)
    );
  assert(
    (ast_id(typeargs) == TK_TYPEARGS) ||
    (ast_id(typeargs) == TK_NONE)
    );

  size_t param_count = ast_childcount(typeparams);
  size_t arg_count = ast_childcount(typeargs);

  if(param_count == arg_count)
    return true;

  if(param_count < arg_count)
  {
    if(errors)
    {
      ast_error(opt->check.errors, typeargs, "too many type arguments");
      ast_error_continue(opt->check.errors, typeparams, "definition is here");
    }

    return false;
  }

  // Pick up default type arguments if they exist.
  ast_setid(typeargs, TK_TYPEARGS);
  ast_t* typeparam = ast_childidx(typeparams, arg_count);

  while(typeparam != NULL)
  {
    ast_t* defarg = ast_childidx(typeparam, 2);

    if(ast_id(defarg) == TK_NONE)
      break;

    ast_append(typeargs, defarg);
    typeparam = ast_sibling(typeparam);
  }

  if(typeparam != NULL)
  {
    if(errors)
    {
      ast_error(opt->check.errors, typeargs, "not enough type arguments");
      ast_error_continue(opt->check.errors, typeparams, "definition is here");
    }

    return false;
  }

  return true;
}
Exemple #4
0
ast_t* type_isect_fun(ast_t* a, ast_t* b)
{
  token_id ta = ast_id(a);
  token_id tb = ast_id(b);

  if(((ta == TK_NEW) || (tb == TK_NEW)) && (ta != tb))
    return NULL;

  AST_GET_CHILDREN(a, a_cap, a_id, a_typeparams, a_params, a_result, a_throw);
  AST_GET_CHILDREN(b, b_cap, b_id, b_typeparams, b_params, b_result, b_throw);

  // Must have the same name.
  if(ast_name(a_id) != ast_name(b_id))
    return NULL;

  // Must have the same number of type parameters and parameters.
  if((ast_childcount(a_typeparams) != ast_childcount(b_typeparams)) ||
    (ast_childcount(a_params) != ast_childcount(b_params)))
    return NULL;

  // Contravariant receiver cap.
  token_id tcap;
  token_id a_tcap = ast_id(a_cap);
  token_id b_tcap = ast_id(b_cap);

  if(is_cap_sub_cap(b_tcap, TK_NONE, a_tcap, TK_NONE))
    tcap = a_tcap;
  else if(is_cap_sub_cap(a_tcap, TK_NONE, b_tcap, TK_NONE))
    tcap = b_tcap;
  else
    tcap = TK_BOX;

  // Result is the intersection of the results.
  ast_t* result = type_isect(a_result, b_result);

  // Covariant throws.
  token_id throws;

  if((ast_id(a_throw) == TK_NONE) || (ast_id(b_throw) == TK_NONE))
    throws = TK_NONE;
  else
    throws = TK_QUESTION;

  BUILD(fun, a,
    NODE(tcap)
    TREE(a_id)
    NODE(TK_TYPEPARAMS)
    NODE(TK_PARAMS)
    TREE(result)
    NODE(throws)
    );

  // TODO: union typeparams and params
  // handling typeparam names is tricky
  return fun;
}
Exemple #5
0
static LLVMValueRef tuple_is(compile_t* c, ast_t* left_type, ast_t* right_type,
  LLVMValueRef l_value, LLVMValueRef r_value)
{
  pony_assert(ast_id(left_type) == TK_TUPLETYPE);
  pony_assert(ast_id(right_type) == TK_TUPLETYPE);
  pony_assert(ast_childcount(left_type) == ast_childcount(right_type));

  // Pairwise comparison.
  LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder);
  LLVMBasicBlockRef post_block = codegen_block(c, "post");

  // Set up the phi node.
  LLVMPositionBuilderAtEnd(c->builder, post_block);
  LLVMValueRef phi = LLVMBuildPhi(c->builder, c->i1, "");

  ast_t* left_child = ast_child(left_type);
  ast_t* right_child = ast_child(right_type);
  int i = 0;

  while(left_child != NULL)
  {
    // Set up the next block.
    LLVMBasicBlockRef next_block = codegen_block(c, "next");
    LLVMPositionBuilderAtEnd(c->builder, this_block);

    // Test the element.
    LLVMValueRef l_elem = LLVMBuildExtractValue(c->builder, l_value, i, "");
    LLVMValueRef r_elem = LLVMBuildExtractValue(c->builder, r_value, i, "");
    LLVMValueRef test = gen_is_value(c, left_child, right_child, l_elem,
      r_elem);

    // If false, go directly to the post block.
    LLVMBuildCondBr(c->builder, test, next_block, post_block);
    LLVMBasicBlockRef current_block = LLVMGetInsertBlock(c->builder);
    LLVMAddIncoming(phi, &test, &current_block, 1);

    // Point to the next block.
    this_block = next_block;

    left_child = ast_sibling(left_child);
    right_child = ast_sibling(right_child);
    i++;
  }

  // The last block is reached if every element returns true. Jump directly to
  // the post block.
  LLVMPositionBuilderAtEnd(c->builder, this_block);
  LLVMBuildBr(c->builder, post_block);

  LLVMPositionBuilderAtEnd(c->builder, post_block);
  LLVMValueRef one = LLVMConstInt(c->i1, 1, false);
  LLVMAddIncoming(phi, &one, &this_block, 1);

  return phi;
}
Exemple #6
0
static void type_append(printbuf_t* buf, ast_t* type, bool first)
{
  switch(ast_id(type))
  {
    case TK_UNIONTYPE:
    {
      // u3_Arg1_Arg2_Arg3
      printbuf(buf, "u%d", ast_childcount(type));
      types_append(buf, type);
      return;
    }

    case TK_ISECTTYPE:
    {
      // i3_Arg1_Arg2_Arg3
      printbuf(buf, "i%d", ast_childcount(type));
      types_append(buf, type);
      return;
    }

    case TK_TUPLETYPE:
    {
      // t3_Arg1_Arg2_Arg3
      printbuf(buf, "t%d", ast_childcount(type));
      types_append(buf, type);
      return;
    }

    case TK_NOMINAL:
    {
      // pkg_Type[_Arg1_Arg2]_cap
      AST_GET_CHILDREN(type, package, name, typeargs, cap, eph);

      ast_t* def = (ast_t*)ast_data(type);
      ast_t* pkg = ast_nearest(def, TK_PACKAGE);
      const char* pkg_name = package_symbol(pkg);

      if(pkg_name != NULL)
        printbuf(buf, "%s_", pkg_name);

      printbuf(buf, "%s", ast_name(name));
      types_append(buf, typeargs);

      if(!first)
        printbuf(buf, "_%s", ast_get_print(cap));

      return;
    }

    default: {}
  }

  assert(0);
}
Exemple #7
0
// Determine the UIF types that the given type may be
static int uifset(pass_opt_t* opt, ast_t* type, lit_chain_t* chain)
{
  assert(chain != NULL);

  if(is_typecheck_error(type))
    return UIF_NO_TYPES;

  switch(ast_id(type))
  {
    case TK_UNIONTYPE:
      return uifset_union(opt, type, chain);

    case TK_ISECTTYPE:
      return uifset_intersect(opt, type, chain);

    case TK_ARROW:
      // Since we don't care about capabilities we can just use the rhs
      assert(ast_id(ast_childidx(type, 1)) == TK_NOMINAL);
      return uifset(opt, ast_childidx(type, 1), chain);

    case TK_TYPEPARAMREF:
      if(chain->cardinality != CHAIN_CARD_BASE) // Incorrect cardinality
        return UIF_NO_TYPES;

      return uifset_formal_param(opt, type, chain);

    case TK_TUPLETYPE:
      if(chain->cardinality != ast_childcount(type)) // Incorrect cardinality
        return UIF_NO_TYPES;

      return uifset(opt, ast_childidx(type, chain->index), chain->next);

    case TK_NOMINAL:
      if(strcmp(ast_name(ast_childidx(type, 1)), "Array") == 0)
      {
        if(chain->cardinality != CHAIN_CARD_ARRAY) // Incorrect cardinality
          return UIF_NO_TYPES;

        ast_t* type_args = ast_childidx(type, 2);
        assert(ast_childcount(type_args) == 1);
        return uifset(opt, ast_child(type_args), chain->next);
      }

      if(chain->cardinality != CHAIN_CARD_BASE) // Incorrect cardinality
        return UIF_NO_TYPES;

      return uifset_simple_type(opt, type);

    default:
      ast_error(type, "Internal error: uif type, node %d", ast_id(type));
      assert(0);
      return UIF_ERROR;
  }
}
Exemple #8
0
static void handle_stack(reachable_method_stack_t* s, reachable_types_t* r,
  uint32_t* next_type_id)
{
  while(s != NULL)
  {
    reachable_method_t* m;
    s = reachable_method_stack_pop(s, &m);

    AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error,
      body);

    m->param_count = ast_childcount(params);
    m->params = (reachable_type_t**)ponyint_pool_alloc_size(
      m->param_count * sizeof(reachable_type_t*));

    ast_t* param = ast_child(params);
    size_t i = 0;

    while(param != NULL)
    {
      AST_GET_CHILDREN(param, p_id, p_type);
      m->params[i++] = add_type(&s, r, next_type_id, p_type);
      param = ast_sibling(param);
    }

    m->result = add_type(&s, r, next_type_id, result);
    reachable_expr(&s, r, next_type_id, body);
  }
}
Exemple #9
0
static ast_result_t flatten_isect(pass_opt_t* opt, ast_t* ast)
{
  // Flatten intersections without testing subtyping. This is to preserve any
  // type guarantees that an element in the intersection might make.
  // If there are more than 2 children, this has already been flattened.
  if(ast_childcount(ast) > 2)
    return AST_OK;

  AST_EXTRACT_CHILDREN(ast, left, right);

  if((opt->check.frame->constraint == NULL) &&
    (opt->check.frame->iftype_constraint == NULL) &&
    (opt->check.frame->provides == NULL) &&
    !is_compat_type(left, right))
  {
    ast_add(ast, right);
    ast_add(ast, left);

    ast_error(opt->check.errors, ast,
      "intersection types cannot include reference capabilities that are not "
      "locally compatible");
    return AST_ERROR;
  }

  flatten_typeexpr_element(ast, left, TK_ISECTTYPE);
  flatten_typeexpr_element(ast, right, TK_ISECTTYPE);

  return AST_OK;
}
Exemple #10
0
static bool verify_main_create(pass_opt_t* opt, ast_t* ast)
{
  if(ast_id(opt->check.frame->type) != TK_ACTOR)
    return true;

  ast_t* type_id = ast_child(opt->check.frame->type);

  if(strcmp(ast_name(type_id), "Main"))
    return true;

  AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error);
  ast_t* type = ast_parent(ast_parent(ast));

  if(strcmp(ast_name(id), "create"))
    return true;

  bool ok = true;

  if(ast_id(ast) != TK_NEW)
  {
    ast_error(opt->check.errors, ast,
      "the create method of the Main actor must be a constructor");
    ok = false;
  }

  if(ast_id(typeparams) != TK_NONE)
  {
    ast_error(opt->check.errors, typeparams,
      "the create constructor of the Main actor must not take type parameters");
    ok = false;
  }

  if(ast_childcount(params) != 1)
  {
    if(ast_pos(params) == ast_pos(type))
      ast_error(opt->check.errors, params,
        "The Main actor must have a create constructor which takes only a "
        "single Env parameter");
    else
      ast_error(opt->check.errors, params,
        "the create constructor of the Main actor must take only a single Env"
        "parameter");
    ok = false;
  }

  ast_t* param = ast_child(params);

  if(param != NULL)
  {
    ast_t* p_type = ast_childidx(param, 1);

    if(!is_env(p_type))
    {
      ast_error(opt->check.errors, p_type, "must be of type Env");
      ok = false;
    }
  }

  return ok;
}
Exemple #11
0
static reachable_type_t* add_tuple(reachable_method_stack_t** s,
  reachable_types_t* r, uint32_t* next_type_id, ast_t* type)
{
  if(contains_dontcare(type))
    return NULL;

  reachable_type_t* t = reach_type(r, type);

  if(t != NULL)
    return t;

  t = add_reachable_type(r, type);
  t->type_id = ++(*next_type_id);

  t->field_count = (uint32_t)ast_childcount(t->ast);
  t->fields = (reachable_field_t*)calloc(t->field_count,
    sizeof(reachable_field_t));
  size_t index = 0;

  ast_t* child = ast_child(type);

  while(child != NULL)
  {
    t->fields[index].ast = ast_dup(child);
    t->fields[index].type = add_type(s, r, next_type_id, child);;
    index++;

    child = ast_sibling(child);
  }

  return t;
}
Exemple #12
0
static bool void_star_param(ast_t* param_type, ast_t* arg_type)
{
  assert(param_type != NULL);
  assert(arg_type != NULL);

  if(!is_pointer(param_type))
    return false;

  ast_t* type_args = ast_childidx(param_type, 2);

  if(ast_childcount(type_args) != 1 || !is_none(ast_child(type_args)))
    return false;

  // Parameter type is Pointer[None]
  // If the argument is Pointer[A], MaybePointer[A] or USize, allow it
  while(ast_id(arg_type) == TK_ARROW)
    arg_type = ast_childidx(arg_type, 1);

  if(is_pointer(arg_type) ||
    is_maybe(arg_type) ||
    is_literal(arg_type, "USize"))
    return true;

  return false;
}
Exemple #13
0
static void set_method_types(reach_t* r, reach_method_t* m,
  pass_opt_t* opt)
{
  AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error,
    body);

  m->param_count = ast_childcount(params);
  m->params = (reach_param_t*)ponyint_pool_alloc_size(
    m->param_count * sizeof(reach_param_t));

  ast_t* param = ast_child(params);
  size_t i = 0;

  while(param != NULL)
  {
    AST_GET_CHILDREN(param, p_id, p_type);
    m->params[i].type = add_type(r, p_type, opt);
    if(ast_id(p_type) != TK_NOMINAL && ast_id(p_type) != TK_TYPEPARAMREF)
      m->params[i].cap = TK_REF;
    else
      m->params[i].cap = ast_id(cap_fetch(p_type));
    ++i;
    param = ast_sibling(param);
  }

  m->result = add_type(r, result, opt);
}
Exemple #14
0
static ast_result_t syntax_compile_error(pass_opt_t* opt, ast_t* ast)
{
  ast_t* parent = ast_parent(ast);
  assert(ast_id(parent) == TK_SEQ);

  if(ast_id(ast_parent(parent)) != TK_IFDEF)
  {
    ast_error(opt->check.errors, ast, "a compile error must be in an ifdef");
    return AST_ERROR;
  }

  // AST must be of the form:
  // (compile_error (seq "Reason"))
  ast_t* reason_seq = ast_child(ast);

  if(ast_id(reason_seq) != TK_SEQ ||
    ast_id(ast_child(reason_seq)) != TK_STRING)
  {
    ast_error(opt->check.errors, ast,
      "a compile error must have a string literal reason for the error");
    return AST_ERROR;
  }

  ast_t* child = ast_child(parent);

  if((child != ast) || (ast_sibling(child) != NULL) ||
    (ast_childcount(reason_seq) != 1))
  {
    ast_error(opt->check.errors, ast,
      "a compile error must be the entire ifdef clause");
    return AST_ERROR;
  }

  return AST_OK;
}
Exemple #15
0
static void find_possible_fun_defs(pass_opt_t* opt, ast_t* ast,
  astlist_t** fun_defs, astlist_t** obj_caps)
{
  switch(ast_id(ast))
  {
    case TK_NOMINAL:
    {
      // A lambda type definition must be an interface.
      ast_t* def = (ast_t*)ast_data(ast);
      if(ast_id(def) != TK_INTERFACE)
        return;

      // The interface must specify just one method in its members.
      ast_t* members = ast_childidx(def, 4);
      pony_assert(ast_id(members) == TK_MEMBERS);
      if(ast_childcount(members) != 1)
        return;

      // That one method is the fun def that we're looking for.
      ast_t* fun_def = ast_child(members);

      // If the interface type has type parameters, we need to reify.
      ast_t* typeargs = ast_childidx(ast, 2);
      ast_t* typeparams = ast_childidx(def, 1);
      if((ast_id(typeargs) == TK_TYPEARGS) &&
        (ast_id(typeparams) == TK_TYPEPARAMS)
        )
        fun_def = reify_method_def(fun_def, typeparams, typeargs, opt);

      // Return the object cap and the method definition.
      *obj_caps = astlist_push(*obj_caps, ast_childidx(ast, 3));
      *fun_defs = astlist_push(*fun_defs, fun_def);
      break;
    }

    case TK_ARROW:
      find_possible_fun_defs(opt, ast_childidx(ast, 1), fun_defs, obj_caps);
      break;

    case TK_TYPEPARAMREF:
    {
      ast_t* def = (ast_t*)ast_data(ast);
      pony_assert(ast_id(def) == TK_TYPEPARAM);
      find_possible_fun_defs(opt, ast_childidx(def, 1), fun_defs, obj_caps);
      break;
    }

    case TK_UNIONTYPE:
    case TK_ISECTTYPE:
    {
      for(ast_t* c = ast_child(ast); c != NULL; c = ast_sibling(c))
        find_possible_fun_defs(opt, c, fun_defs, obj_caps);
      break;
    }

    default:
      break;
  }
}
Exemple #16
0
static bool verify_any_final(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body);

  if(strcmp(ast_name(id), "_final"))
    return true;

  bool ok = true;

  if((ast_id(opt->check.frame->type) == TK_PRIMITIVE) &&
    (ast_id(ast_childidx(opt->check.frame->type, 1)) != TK_NONE))
  {
    ast_error(opt->check.errors, ast,
      "a primitive with type parameters cannot have a _final method");
    ok = false;
  }

  if(ast_id(ast) != TK_FUN)
  {
    ast_error(opt->check.errors, ast, "a _final method must be a function");
    ok = false;
  }

  if(ast_id(cap) != TK_BOX)
  {
    ast_error(opt->check.errors, cap,
      "a _final method must use box as the receiver capability");
    ok = false;
  }

  if(ast_id(typeparams) != TK_NONE)
  {
    ast_error(opt->check.errors, typeparams,
      "a _final method must not take type parameters");
    ok = false;
  }

  if(ast_childcount(params) != 0)
  {
    ast_error(opt->check.errors, params,
      "a _final method must take no parameters");
    ok = false;
  }

  if(!is_none(result))
  {
    ast_error(opt->check.errors, result, "a _final method must return None");
    ok = false;
  }

  if(ast_id(can_error) != TK_NONE)
  {
    ast_error(opt->check.errors, can_error,
      "a _final method cannot be a partial function");
    ok = false;
  }

  return ok;
}
Exemple #17
0
static void genfun_dwarf(compile_t* c, gentype_t* g, const char *name,
  ast_t* typeargs, ast_t* fun)
{
  if(!codegen_hassource(c))
    return;

  // Get the function.
  const char* funname = genname_fun(g->type_name, name, typeargs);
  LLVMValueRef func = LLVMGetNamedFunction(c->module, funname);
  assert(func != NULL);

  // Count the parameters, including the receiver.
  ast_t* params = ast_childidx(fun, 3);
  size_t count = ast_childcount(params) + 1;

  size_t buf_size = (count + 1) * sizeof(const char*);
  const char** pnames = (const char**)pool_alloc_size(buf_size);
  count = 0;

  // Return value type name and receiver type name.
  pnames[count++] = genname_type(ast_childidx(fun, 4));
  pnames[count++] = g->type_name;

  // Get a type name for each parameter.
  ast_t* param = ast_child(params);

  while(param != NULL)
  {
    ast_t* ptype = ast_childidx(param, 1);
    pnames[count++] = genname_type(ptype);
    param = ast_sibling(param);
  }

  // Dwarf the method type
  dwarf_method(&c->dwarf, fun, name, funname, pnames, count, func);

  // Dwarf the receiver pointer.
  LLVMBasicBlockRef entry = LLVMGetEntryBasicBlock(codegen_fun(c));
  LLVMValueRef argument = codegen_getlocal(c, stringtab("this"));

  dwarf_this(&c->dwarf, fun, g->type_name, entry, argument);

  // Dwarf locals for parameters
  param = ast_child(params);
  size_t index = 1;

  while(param != NULL)
  {
    argument = codegen_getlocal(c, ast_name(ast_child(param)));
    dwarf_parameter(&c->dwarf, param, pnames[index + 1], entry, argument,
      index);
    param = ast_sibling(param);
    index++;
  }

  pool_free_size(buf_size, pnames);
}
Exemple #18
0
static bool check_finaliser(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body);

  if(strcmp(ast_name(id), "_final"))
    return true;

  bool ok = true;

  if((ast_id(opt->check.frame->type) == TK_PRIMITIVE) &&
    (ast_id(ast_childidx(opt->check.frame->type, 1)) != TK_NONE))
  {
    ast_error(opt->check.errors, ast,
      "a primitive with type parameters cannot have a _final");
    ok = false;
  }

  if(ast_id(ast) != TK_FUN)
  {
    ast_error(opt->check.errors, ast, "_final must be a function");
    ok = false;
  }

  if(ast_id(cap) != TK_BOX)
  {
    ast_error(opt->check.errors, cap, "_final must be box");
    ok = false;
  }

  if(ast_id(typeparams) != TK_NONE)
  {
    ast_error(opt->check.errors, typeparams, "_final must not be polymorphic");
    ok = false;
  }

  if(ast_childcount(params) != 0)
  {
    ast_error(opt->check.errors, params, "_final must not have parameters");
    ok = false;
  }

  if(!is_none(result))
  {
    ast_error(opt->check.errors, result, "_final must return None");
    ok = false;
  }

  if(ast_id(can_error) != TK_NONE)
  {
    ast_error(opt->check.errors, can_error, "_final cannot raise an error");
    ok = false;
  }

  return ok;
}
Exemple #19
0
static void add_as_type(typecheck_t* t, ast_t* type, ast_t* pattern,
  ast_t* body)
{
  assert(type != NULL);

  switch(ast_id(type))
  {
    case TK_TUPLETYPE:
    {
      BUILD(tuple_pattern, pattern, NODE(TK_SEQ, NODE(TK_TUPLE)));
      ast_append(pattern, tuple_pattern);
      ast_t* pattern_child = ast_child(tuple_pattern);

      BUILD(tuple_body, body, NODE(TK_SEQ, NODE(TK_TUPLE)));
      ast_t* body_child = ast_child(tuple_body);

      for(ast_t* p = ast_child(type); p != NULL; p = ast_sibling(p))
        add_as_type(t, p, pattern_child, body_child);

      if(ast_childcount(body_child) == 1)
      {
        // Only one child, not actually a tuple
        ast_t* t = ast_pop(body_child);
        ast_free(tuple_body);
        tuple_body = t;
      }

      ast_append(body, tuple_body);
      break;
    }

    case TK_DONTCARE:
      ast_append(pattern, type);
      break;

    default:
    {
      const char* name = package_hygienic_id(t);
      ast_t* a_type = alias(type);

      BUILD(pattern_elem, pattern,
        NODE(TK_SEQ,
          NODE(TK_LET, ID(name) TREE(a_type))));

      BUILD(body_elem, body,
        NODE(TK_SEQ,
          NODE(TK_CONSUME, NODE(TK_BORROWED) NODE(TK_REFERENCE, ID(name)))));

      ast_append(pattern, pattern_elem);
      ast_append(body, body_elem);
      break;
    }
  }
}
Exemple #20
0
static bool check_tuple(compile_t* c, LLVMValueRef ptr, LLVMValueRef desc,
  ast_t* pattern_type, LLVMBasicBlockRef next_block)
{
  // First check cardinality.
  size_t size = ast_childcount(pattern_type);
  check_cardinality(c, desc, size, next_block);

  // If we get here, the match expression has the right cardinality.
  ast_t* pattern_child = ast_child(pattern_type);

  for(int i = 0; pattern_child != NULL; i++)
  {
    // Get the field offset and field descriptor from the tuple descriptor.
    LLVMValueRef field_info = gendesc_fieldinfo(c, desc, i);
    LLVMValueRef field_ptr = gendesc_fieldptr(c, ptr, field_info);
    LLVMValueRef field_desc = gendesc_fielddesc(c, field_info);

    // If we have a null descriptor, load the object.
    LLVMBasicBlockRef null_block = codegen_block(c, "null_desc");
    LLVMBasicBlockRef nonnull_block = codegen_block(c, "nonnull_desc");
    LLVMBasicBlockRef continue_block = codegen_block(c, "merge_desc");
    LLVMValueRef test = LLVMBuildIsNull(c->builder, field_desc, "");
    LLVMBuildCondBr(c->builder, test, null_block, nonnull_block);

    // Load the object, load its descriptor, and continue from there.
    LLVMPositionBuilderAtEnd(c->builder, null_block);
    LLVMTypeRef ptr_type = LLVMPointerType(c->object_ptr, 0);
    LLVMValueRef object_ptr = LLVMBuildIntToPtr(c->builder, field_ptr,
      ptr_type, "");
    LLVMValueRef object = LLVMBuildLoad(c->builder, object_ptr, "");
    LLVMValueRef object_desc = gendesc_fetch(c, object);
    object_ptr = gendesc_ptr_to_fields(c, object, object_desc);

    if(!check_type(c, object_ptr, object_desc, pattern_child, next_block))
      return false;

    LLVMBuildBr(c->builder, continue_block);

    // Continue with the pointer and descriptor.
    LLVMPositionBuilderAtEnd(c->builder, nonnull_block);

    if(!check_type(c, field_ptr, field_desc, pattern_child, next_block))
      return false;

    LLVMBuildBr(c->builder, continue_block);

    // Merge the two branches.
    LLVMPositionBuilderAtEnd(c->builder, continue_block);
    pattern_child = ast_sibling(pattern_child);
  }

  return true;
}
Exemple #21
0
static bool extend_positional_args(ast_t* params, ast_t* positional)
{
  // Fill out the positional args to be as long as the param list.
  size_t param_len = ast_childcount(params);
  size_t arg_len = ast_childcount(positional);

  if(arg_len > param_len)
  {
    ast_error(positional, "too many arguments");
    return false;
  }

  while(arg_len < param_len)
  {
    ast_setid(positional, TK_POSITIONALARGS);
    ast_append(positional, ast_from(positional, TK_NONE));
    arg_len++;
  }

  return true;
}
Exemple #22
0
static bool is_tuple_sub_tuple(ast_t* sub, ast_t* super, errorframe_t* errors)
{
  // T1 <: T3
  // T2 <: T4
  // ---
  // (T1, T2) <: (T3, T4)
  if(ast_childcount(sub) != ast_childcount(super))
  {
    if(errors != NULL)
    {
      ast_error_frame(errors, sub,
        "%s is not a subtype of %s: they have a different number of elements",
        ast_print_type(sub), ast_print_type(super));
    }

    return false;
  }

  ast_t* sub_child = ast_child(sub);
  ast_t* super_child = ast_child(super);
  bool ret = true;

  while(sub_child != NULL)
  {
    if(!is_subtype(sub_child, super_child, errors))
      ret = false;

    sub_child = ast_sibling(sub_child);
    super_child = ast_sibling(super_child);
  }

  if(!ret && errors != NULL)
  {
    ast_error_frame(errors, sub, "%s is not a pairwise subtype of %s",
      ast_print_type(sub), ast_print_type(super));
  }

  return ret;
}
Exemple #23
0
static void setup_tuple_fields(gentype_t* g)
{
  g->field_count = (int)ast_childcount(g->ast);
  g->fields = (ast_t**)calloc(g->field_count, sizeof(ast_t*));

  ast_t* child = ast_child(g->ast);
  size_t index = 0;

  while(child != NULL)
  {
    g->fields[index++] = child;
    child = ast_sibling(child);
  }
}
Exemple #24
0
static LLVMTypeRef get_signature(compile_t* c, gentype_t* g, ast_t* fun)
{
  // Get a type for the result.
  ast_t* rtype = ast_childidx(fun, 4);
  gentype_t rtype_g;

  if(!gentype(c, rtype, &rtype_g))
  {
    ast_error(rtype, "couldn't generate result type");
    return NULL;
  }

  // Count the parameters, including the receiver.
  ast_t* params = ast_childidx(fun, 3);
  size_t count = ast_childcount(params) + 1;

  size_t buf_size = count *sizeof(LLVMTypeRef);
  LLVMTypeRef* tparams = (LLVMTypeRef*)pool_alloc_size(buf_size);
  count = 0;

  // Get a type for the receiver.
  tparams[count++] = g->use_type;

  // Get a type for each parameter.
  ast_t* param = ast_child(params);

  while(param != NULL)
  {
    ast_t* ptype = ast_childidx(param, 1);
    gentype_t ptype_g;

    if(!gentype(c, ptype, &ptype_g))
    {
      ast_error(ptype, "couldn't generate parameter type");
      pool_free_size(buf_size, tparams);
      return NULL;
    }

    tparams[count++] = ptype_g.use_type;
    param = ast_sibling(param);
  }

  LLVMTypeRef result = rtype_g.use_type;

  // Generate the function type.
  LLVMTypeRef r = LLVMFunctionType(result, tparams, (int)count, false);

  pool_free_size(buf_size, tparams);
  return r;
}
Exemple #25
0
static ast_result_t flatten_union(pass_opt_t* opt, ast_t* ast)
{
  (void)opt;
  // Flatten unions without testing subtyping. This will be tested after the
  // traits pass, when we have full subtyping information.
  // If there are more than 2 children, this has already been flattened.
  if(ast_childcount(ast) > 2)
    return AST_OK;

  AST_EXTRACT_CHILDREN(ast, left, right);

  flatten_typeexpr_element(ast, left, TK_UNIONTYPE);
  flatten_typeexpr_element(ast, right, TK_UNIONTYPE);

  return AST_OK;
}
Exemple #26
0
static bool check_main_create(typecheck_t* t, ast_t* ast)
{
  if(ast_id(t->frame->type) != TK_ACTOR)
    return true;

  ast_t* type_id = ast_child(t->frame->type);

  if(strcmp(ast_name(type_id), "Main"))
    return true;

  AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error);

  if(strcmp(ast_name(id), "create"))
    return true;

  bool ok = true;

  if(ast_id(typeparams) != TK_NONE)
  {
    ast_error(typeparams,
      "the create constructor of a Main actor must not be polymorphic");
    ok = false;
  }

  if(ast_childcount(params) != 1)
  {
    ast_error(params,
      "the create constructor of a Main actor must take a single Env "
      "parameter");
    ok = false;
  }

  ast_t* param = ast_child(params);

  if(param != NULL)
  {
    ast_t* p_type = ast_childidx(param, 1);

    if(!is_env(p_type))
    {
      ast_error(p_type, "must be of type Env");
      ok = false;
    }
  }

  return ok;
}
Exemple #27
0
static bool check_finaliser(ast_t* ast)
{
  AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body);

  if(strcmp(ast_name(id), "_final"))
    return true;

  bool ok = true;

  if(ast_id(ast) != TK_FUN)
  {
    ast_error(ast, "_final must be a function");
    ok = false;
  }

  if(ast_id(cap) != TK_BOX)
  {
    ast_error(cap, "_final must be box");
    ok = false;
  }

  if(ast_id(typeparams) != TK_NONE)
  {
    ast_error(typeparams, "_final must not be polymorphic");
    ok = false;
  }

  if(ast_childcount(params) != 0)
  {
    ast_error(params, "_final must not have parameters");
    ok = false;
  }

  if(!is_none(result))
  {
    ast_error(result, "_final must return None");
    ok = false;
  }

  if(ast_id(can_error) != TK_NONE)
  {
    ast_error(can_error, "_final cannot raise an error");
    ok = false;
  }

  return ok;
}
Exemple #28
0
static void make_global_descriptor(compile_t* c, gentype_t* g)
{
  // Fetch or create a descriptor type.
  if(g->underlying == TK_TUPLETYPE)
    g->field_count = (int)ast_childcount(g->ast);

  // Check for an existing descriptor.
  g->desc_type = gendesc_type(c, g);
  g->desc = LLVMGetNamedGlobal(c->module, g->desc_name);

  if(g->desc != NULL)
    return;

  g->desc = LLVMAddGlobal(c->module, g->desc_type, g->desc_name);
  LLVMSetGlobalConstant(g->desc, true);
  LLVMSetLinkage(g->desc, LLVMInternalLinkage);
}
Exemple #29
0
static bool tuple_access(pass_opt_t* opt, ast_t* ast)
{
  // Left is a postfix expression, right is a lookup name.
  ast_t* left = ast_child(ast);
  ast_t* right = ast_sibling(left);
  ast_t* type = ast_type(left);

  if(is_typecheck_error(type))
    return false;

  // Change the lookup name to an integer index.
  if(!make_tuple_index(&right))
  {
    ast_error(opt->check.errors, right,
      "lookup on a tuple must take the form _X, where X is an integer");
    return false;
  }

  // Make sure our index is in bounds.  make_tuple_index automatically shifts
  // from one indexed to zero, so we have to use -1 and >= for our comparisons.
  size_t right_idx = (size_t)ast_int(right)->low;
  size_t tuple_size = ast_childcount(type);

  if (right_idx == (size_t)-1)
  {
    ast_error(opt->check.errors, right,
      "tuples are one indexed not zero indexed. Did you mean _1?");
    return false;
  }
  else if (right_idx >= tuple_size)
  {
    ast_error(opt->check.errors, right, "tuple index " __zu " is out of "
      "valid range. Valid range is [1, " __zu "]", right_idx, tuple_size);
    return false;
  }

  type = ast_childidx(type, right_idx);
  assert(type != NULL);

  ast_setid(ast, TK_FLETREF);
  ast_settype(ast, type);
  ast_inheritflags(ast);
  return true;
}
Exemple #30
0
static ast_result_t syntax_return(pass_opt_t* opt, ast_t* ast,
  size_t max_value_count)
{
  assert(ast != NULL);

  ast_t* value_seq = ast_child(ast);
  assert(ast_id(value_seq) == TK_SEQ || ast_id(value_seq) == TK_NONE);
  size_t value_count = ast_childcount(value_seq);

  if(value_count > max_value_count)
  {
    ast_error(opt->check.errors,
      ast_childidx(value_seq, max_value_count), "Unreachable code");
    return AST_ERROR;
  }

  if(ast_id(ast) == TK_RETURN)
  {
    if(opt->check.frame->method_body == NULL)
    {
      ast_error(opt->check.errors, ast, "return must occur in a method body");
      return AST_ERROR;
    }

    if(value_count > 0)
    {
      if(ast_id(opt->check.frame->method) == TK_NEW)
      {
        ast_error(opt->check.errors, ast,
          "A return in a constructor must not have an expression");
        return AST_ERROR;
      }

      if(ast_id(opt->check.frame->method) == TK_BE)
      {
        ast_error(opt->check.errors, ast,
          "A return in a behaviour must not have an expression");
        return AST_ERROR;
      }
    }
  }

  return AST_OK;
}