Beispiel #1
0
static bool genfun_new(compile_t* c, reachable_type_t* t,
  reachable_method_t* m)
{
  assert(m->func != NULL);

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

  codegen_startfun(c, m->func, m->di_file, m->di_method);
  name_params(c, t, m, params, m->func);

  LLVMValueRef value = gen_expr(c, body);

  if(value == NULL)
    return false;

  // Return 'this'.
  if(t->primitive == NULL)
    value = LLVMGetParam(m->func, 0);

  codegen_debugloc(c, ast_childlast(body));
  LLVMBuildRet(c->builder, value);
  codegen_debugloc(c, NULL);

  codegen_finishfun(c);
  return true;
}
Beispiel #2
0
void fun_defaults(ast_t* ast)
{
  assert(ast != NULL);
  AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body,
    docstring);

  // If the receiver cap is not specified, set it to box.
  if(ast_id(cap) == TK_NONE)
    ast_setid(cap, TK_BOX);

  // If the return value is not specified, set it to None.
  if(ast_id(result) == TK_NONE)
  {
    ast_t* type = type_sugar(ast, NULL, "None");
    ast_replace(&result, type);
  }

  // If the return type is None, add a None at the end of the body, unless it
  // already ends with an error or return statement
  if(is_none(result) && (ast_id(body) != TK_NONE))
  {
    ast_t* last_cmd = ast_childlast(body);

    if(ast_id(last_cmd) != TK_ERROR && ast_id(last_cmd) != TK_RETURN)
    {
      BUILD_NO_DEBUG(ref, body, NODE(TK_REFERENCE, ID("None")));
      ast_append(body, ref);
    }
  }
}
Beispiel #3
0
static bool check_embed_construction(pass_opt_t* opt, ast_t* left, ast_t* right)
{
  bool result = true;
  if(ast_id(left) == TK_EMBEDREF)
  {
    if(!is_expr_constructor(right))
    {
      ast_error(opt->check.errors, left,
        "an embedded field must be assigned using a constructor");
      ast_error_continue(opt->check.errors, right,
        "the assigned expression is here");
      return false;
    }
  } else if(ast_id(left) == TK_TUPLE) {
    if(ast_id(right) == TK_TUPLE)
    {
      ast_t* l_child = ast_child(left);
      ast_t* r_child = ast_child(right);
      while(l_child != NULL)
      {
        if(ast_id(l_child) != TK_DONTCARE)
        {
          assert((ast_id(l_child) == TK_SEQ) && (ast_id(r_child) == TK_SEQ));
          ast_t* l_member = ast_childlast(l_child);
          ast_t* r_member = ast_childlast(r_child);
          if(!check_embed_construction(opt, l_member, r_member))
            result = false;
        }
        l_child = ast_sibling(l_child);
        r_child = ast_sibling(r_child);
      }
      assert(r_child == NULL);
    } else if(tuple_contains_embed(left)) {
      ast_error(opt->check.errors, left,
        "an embedded field must be assigned using a constructor");
      ast_error_continue(opt->check.errors, right,
        "the assigned expression isn't a tuple literal");
    }
  }
  return result;
}
Beispiel #4
0
// Process the method provided to the given entity.
// Stage 2.
static bool provided_methods(ast_t* entity)
{
  assert(entity != NULL);

  ast_t* provides = ast_childidx(entity, 3);
  ast_t* entity_members = ast_childidx(entity, 4);
  ast_t* last_member = ast_childlast(entity_members);
  bool r = true;

  // Run through our provides list
  for(ast_t* p = ast_child(provides); p != NULL; p = ast_sibling(p))
  {
    ast_t* trait_def = (ast_t*)ast_data(p);
    assert(trait_def != NULL);

    ast_t* type_args = ast_childidx(p, 2);
    ast_t* type_params = ast_childidx(trait_def, 1);
    ast_t* members = ast_childidx(trait_def, 4);

    // Run through the methods of each provided type
    for(ast_t* m = ast_child(members); m != NULL; m = ast_sibling(m))
    {
      // Check behaviour compatability
      if(ast_id(m) == TK_BE)
      {
        if(ast_id(entity) == TK_PRIMITIVE || ast_id(entity) == TK_CLASS)
        {
          ast_error(entity, "%s can't provide traits that have behaviours",
            (ast_id(entity) == TK_CLASS) ? "classes" : "primitives");

          r = false;
          continue;
        }
      }

      if(is_method(m))
      {
        // We have a provided method
        // Reify the method with the type parameters from trait definition and type
        // arguments from trait reference
        ast_t* reified = reify(type_args, m, type_params, type_args);

        if(reified == NULL) // Reification error, already reported
          return false;

        if(!provided_method(entity, reified, m, &last_member))
          r = false;
      }
    }
  }

  return r;
}
Beispiel #5
0
static bool genfun_fun(compile_t* c, reachable_type_t* t,
  reachable_method_t* m)
{
  assert(m->func != NULL);

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

  if(m->name == c->str__final)
  {
    t->final_fn = m->func;
    LLVMSetFunctionCallConv(m->func, LLVMCCallConv);
  }

  codegen_startfun(c, m->func, m->di_file, m->di_method);
  name_params(c, t, m, params, m->func);

  LLVMValueRef value = gen_expr(c, body);

  if(value == NULL)
    return false;

  if(value != GEN_NOVALUE)
  {
    LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(m->func));
    LLVMTypeRef r_type = LLVMGetReturnType(f_type);

    // If the result type is known to be a tuple, do the correct assignment
    // cast even if the body type is not a tuple.
    ast_t* body_type = ast_type(body);

    if(ast_id(result) == TK_TUPLETYPE)
      body_type = result;

    LLVMValueRef ret = gen_assign_cast(c, r_type, value, body_type);

    if(ret == NULL)
      return false;

    codegen_debugloc(c, ast_childlast(body));
    LLVMBuildRet(c->builder, ret);
    codegen_debugloc(c, NULL);
  }

  codegen_finishfun(c);
  return true;
}
Beispiel #6
0
static bool is_expr_constructor(ast_t* ast)
{
  assert(ast != NULL);
  switch(ast_id(ast))
  {
    case TK_CALL:
      return ast_id(ast_childidx(ast, 2)) == TK_NEWREF;
    case TK_SEQ:
      return is_expr_constructor(ast_childlast(ast));
    case TK_IF:
    case TK_WHILE:
    case TK_REPEAT:
    {
      ast_t* body = ast_childidx(ast, 1);
      ast_t* else_expr = ast_childidx(ast, 2);
      return is_expr_constructor(body) && is_expr_constructor(else_expr);
    }
    case TK_TRY:
    {
      ast_t* body = ast_childidx(ast, 0);
      ast_t* else_expr = ast_childidx(ast, 1);
      return is_expr_constructor(body) && is_expr_constructor(else_expr);
    }
    case TK_MATCH:
    {
      ast_t* cases = ast_childidx(ast, 1);
      ast_t* else_expr = ast_childidx(ast, 2);
      ast_t* the_case = ast_child(cases);

      while(the_case != NULL)
      {
        if(!is_expr_constructor(ast_childidx(the_case, 2)))
          return false;
        the_case = ast_sibling(the_case);
      }
      return is_expr_constructor(else_expr);
    }
    case TK_RECOVER:
      return is_expr_constructor(ast_childidx(ast, 1));
    default:
      return false;
  }
}
Beispiel #7
0
static bool check_return_type(ast_t* ast)
{
  AST_GET_CHILDREN(ast, cap, id, typeparams, params, type, can_error, body);
  ast_t* body_type = ast_type(body);

  if(is_typecheck_error(body_type))
    return false;

  // The last statement is an error, and we've already checked any return
  // expressions in the method.
  if(is_control_type(body_type))
    return true;

  // If it's a compiler intrinsic, ignore it.
  if(ast_id(body_type) == TK_COMPILE_INTRINSIC)
    return true;

  // The body type must match the return type, without subsumption, or an alias
  // of the body type must be a subtype of the return type.
  ast_t* a_type = alias(type);
  ast_t* a_body_type = alias(body_type);
  bool ok = true;

  errorframe_t info = NULL;
  if(!is_subtype(body_type, type, &info) ||
    !is_subtype(a_body_type, a_type, &info))
  {
    errorframe_t frame = NULL;
    ast_t* last = ast_childlast(body);
    ast_error_frame(&frame, last, "function body isn't the result type");
    ast_error_frame(&frame, type, "function return type: %s",
      ast_print_type(type));
    ast_error_frame(&frame, body_type, "function body type: %s",
      ast_print_type(body_type));
    errorframe_append(&frame, &info);
    errorframe_report(&frame);
    ok = false;
  }

  ast_free_unattached(a_type);
  ast_free_unattached(a_body_type);
  return ok;
}
Beispiel #8
0
static bool genfun_newbe(compile_t* c, reachable_type_t* t,
  reachable_method_t* m)
{
  assert(m->func != NULL);
  assert(m->func_handler != NULL);

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

  // Generate the handler.
  codegen_startfun(c, m->func_handler, m->di_file, m->di_method);
  name_params(c, t, m, params, m->func_handler);

  LLVMValueRef value = gen_expr(c, body);

  if(value == NULL)
    return false;

  LLVMBuildRetVoid(c->builder);
  codegen_finishfun(c);

  // Generate the sender.
  codegen_startfun(c, m->func, NULL, NULL);
  LLVMValueRef this_ptr = LLVMGetParam(m->func, 0);

  // Send the arguments in a message to 'this'.
  LLVMTypeRef msg_type_ptr = send_message(c, params, this_ptr, m->func,
    m->vtable_index);

  // Return 'this'.
  codegen_debugloc(c, ast_childlast(body));
  LLVMBuildRet(c->builder, this_ptr);
  codegen_debugloc(c, NULL);

  codegen_finishfun(c);

  // Add the dispatch case.
  add_dispatch_case(c, t, params, m->vtable_index, m->func_handler,
    msg_type_ptr);

  return true;
}
Beispiel #9
0
static bool tuple_contains_embed(ast_t* ast)
{
  assert(ast_id(ast) == TK_TUPLE);
  ast_t* child = ast_child(ast);
  while(child != NULL)
  {
    if(ast_id(child) != TK_DONTCARE)
    {
      assert(ast_id(child) == TK_SEQ);
      ast_t* member = ast_childlast(child);
      if(ast_id(member) == TK_EMBEDREF)
      {
        return true;
      } else if(ast_id(member) == TK_TUPLE) {
        if(tuple_contains_embed(member))
          return true;
      }
    }
    child = ast_sibling(child);
  }
  return false;
}
Beispiel #10
0
static LLVMValueRef declare_ffi(compile_t* c, const char* f_name,
  reach_type_t* t, ast_t* args, bool intrinsic)
{
  ast_t* last_arg = ast_childlast(args);

  if((last_arg != NULL) && (ast_id(last_arg) == TK_ELLIPSIS))
    return declare_ffi_vararg(c, f_name, t);

  int count = (int)ast_childcount(args);
  size_t buf_size = count * sizeof(LLVMTypeRef);
  LLVMTypeRef* f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
  count = 0;

  ast_t* arg = ast_child(args);

  deferred_reification_t* reify = c->frame->reify;

  while(arg != NULL)
  {
    ast_t* p_type = ast_type(arg);

    if(p_type == NULL)
      p_type = ast_childidx(arg, 1);

    p_type = deferred_reify(reify, p_type, c->opt);
    reach_type_t* pt = reach_type(c->reach, p_type);
    pony_assert(pt != NULL);
    f_params[count++] = ((compile_type_t*)pt->c_type)->use_type;
    ast_free_unattached(p_type);
    arg = ast_sibling(arg);
  }

  LLVMTypeRef r_type = ffi_return_type(c, t, intrinsic);
  LLVMTypeRef f_type = LLVMFunctionType(r_type, f_params, count, false);
  LLVMValueRef func = LLVMAddFunction(c->module, f_name, f_type);

  ponyint_pool_free_size(buf_size, f_params);
  return func;
}
Beispiel #11
0
static ast_t* find_embed_constructor_receiver(ast_t* call)
{
  call_tuple_indices_t tuple_indices = {NULL, 0, 4};
  tuple_indices_init(&tuple_indices);

  ast_t* parent = make_tuple_indices(&tuple_indices, call);
  ast_t* fieldref = NULL;

  if((parent != NULL) && (ast_id(parent) == TK_ASSIGN))
  {
    // Traverse the LHS of the assignment looking for what our constructor call
    // is assigned to.
    ast_t* current = ast_child(parent);
    while((ast_id(current) == TK_TUPLE) || (ast_id(current) == TK_SEQ))
    {
      parent = current;
      if(ast_id(current) == TK_TUPLE)
      {
        // If there are no indices left, we're destructuring a tuple.
        // Errors in those cases have already been catched by the expr
        // pass.
        if(tuple_indices.count == 0)
          break;

        size_t index = tuple_indices_pop(&tuple_indices);
        current = ast_childidx(parent, index);
      } else {
        current = ast_childlast(parent);
      }
    }

    if(ast_id(current) == TK_EMBEDREF)
      fieldref = current;
  }

  tuple_indices_destroy(&tuple_indices);
  return fieldref;
}
Beispiel #12
0
static ast_result_t sugar_module(ast_t* ast)
{
  ast_t* docstring = ast_child(ast);

  ast_t* package = ast_parent(ast);
  assert(ast_id(package) == TK_PACKAGE);

  if(strcmp(package_name(package), "$0") != 0)
  {
    // Every module not in builtin has an implicit use builtin command.
    // Since builtin is always the first package processed it is $0.
    BUILD(builtin, ast,
      NODE(TK_USE,
      NONE
      STRING(stringtab("builtin"))
      NONE));

    ast_add(ast, builtin);
  }

  if((docstring == NULL) || (ast_id(docstring) != TK_STRING))
    return AST_OK;

  ast_t* package_docstring = ast_childlast(package);

  if(ast_id(package_docstring) == TK_STRING)
  {
    ast_error(docstring, "the package already has a docstring");
    ast_error(package_docstring, "the existing docstring is here");
    return AST_ERROR;
  }

  ast_append(package, docstring);
  ast_remove(docstring);
  return AST_OK;
}
Beispiel #13
0
// Coerce a literal expression to given tuple or non-tuple types
static bool coerce_literal_to_type(ast_t** astp, ast_t* target_type,
  lit_chain_t* chain, pass_opt_t* options, bool report_errors)
{
  assert(astp != NULL);
  ast_t* literal_expr = *astp;
  assert(literal_expr != NULL);

  ast_t* lit_type = ast_type(literal_expr);

  if(lit_type == NULL ||
    (ast_id(lit_type) != TK_LITERAL && ast_id(lit_type) != TK_OPERATORLITERAL))
  {
    // Not a literal
    return true;
  }

  if(ast_child(lit_type) != NULL)
  {
    // Control block literal
    return coerce_control_block(astp, target_type, chain, options,
      report_errors);
  }

  switch(ast_id(literal_expr))
  {
    case TK_TUPLE:  // Tuple literal
    {
      size_t cardinality = ast_childcount(literal_expr);
      if(!coerce_group(astp, target_type, chain, cardinality, options,
        report_errors))
        return false;

      break;
    }

    case TK_INT:
      return uif_type_from_chain(options, literal_expr, target_type, chain,
        false, report_errors);

    case TK_FLOAT:
      return uif_type_from_chain(options, literal_expr, target_type, chain,
        true, report_errors);

    case TK_ARRAY:
      if(!coerce_group(astp, target_type, chain, CHAIN_CARD_ARRAY, options,
        report_errors))
        return false;

      break;

    case TK_SEQ:
    {
      // Only coerce the last expression in the sequence
      ast_t* last = ast_childlast(literal_expr);

      if(!coerce_literal_to_type(&last, target_type, chain, options,
        report_errors))
        return false;

      ast_settype(literal_expr, ast_type(last));
      return true;
    }

    case TK_CALL:
    {
      AST_GET_CHILDREN(literal_expr, positional, named, receiver);
      ast_t* arg = ast_child(positional);

      if(!coerce_literal_to_type(&receiver, target_type, chain, options,
        report_errors))
        return false;

      if(arg != NULL &&
        !coerce_literal_to_type(&arg, target_type, chain, options,
        report_errors))
        return false;

      ast_settype(literal_expr, ast_type(ast_child(receiver)));
      return true;
    }

    case TK_DOT:
    {
      ast_t* receiver = ast_child(literal_expr);
      if(!coerce_literal_to_type(&receiver, target_type, chain, options,
        report_errors))
        return false;

      break;
    }

    default:
      ast_error(literal_expr, "Internal error, coerce_literal_to_type node %s",
        ast_get_print(literal_expr));
      assert(0);
      return false;
  }


  // Need to reprocess node now all the literals have types
  ast_settype(literal_expr, NULL);
  return (pass_expr(astp, options) == AST_OK);
}
Beispiel #14
0
static void genfun_dwarf_return(compile_t* c, ast_t* body)
{
  ast_t* last = ast_childlast(body);
  dwarf_location(&c->dwarf, last);
}
Beispiel #15
0
static LLVMValueRef declare_ffi(compile_t* c, const char* f_name,
  reach_type_t* t, ast_t* args, bool err, bool intrinsic)
{
  ast_t* last_arg = ast_childlast(args);

  if((last_arg != NULL) && (ast_id(last_arg) == TK_ELLIPSIS))
    return declare_ffi_vararg(c, f_name, t, err);

  int count = (int)ast_childcount(args);
  size_t buf_size = count * sizeof(LLVMTypeRef);
  LLVMTypeRef* f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
  count = 0;

  ast_t* arg = ast_child(args);

  while(arg != NULL)
  {
    ast_t* p_type = ast_type(arg);

    if(p_type == NULL)
      p_type = ast_childidx(arg, 1);

    reach_type_t* pt = reach_type(c->reach, p_type);
    pony_assert(pt != NULL);

    // An intrinsic that takes a Bool should be i1, not ibool.
    if(intrinsic && is_bool(pt->ast))
      f_params[count++] = c->i1;
    else
      f_params[count++] = pt->use_type;

    arg = ast_sibling(arg);
  }

  LLVMTypeRef r_type;

  if(t->underlying == TK_TUPLETYPE)
  {
    // Can't use the named type. Build an unnamed type with the same
    // elements.
    unsigned int count = LLVMCountStructElementTypes(t->use_type);
    size_t buf_size = count * sizeof(LLVMTypeRef);
    LLVMTypeRef* e_types = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
    LLVMGetStructElementTypes(t->use_type, e_types);

    if(intrinsic)
    {
      ast_t* child = ast_child(t->ast);
      size_t i = 0;

      while(child != NULL)
      {
        // A Bool in an intrinsic tuple return type is an i1, not an ibool.
        if(is_bool(child))
          e_types[i] = c->i1;

        child = ast_sibling(child);
        i++;
      }
    }

    r_type = LLVMStructTypeInContext(c->context, e_types, count, false);
    ponyint_pool_free_size(buf_size, e_types);
  } else {
    // An intrinsic that returns a Bool returns an i1, not an ibool.
    if(intrinsic && is_bool(t->ast))
      r_type = c->i1;
    else
      r_type = t->use_type;
  }

  LLVMTypeRef f_type = LLVMFunctionType(r_type, f_params, count, false);
  LLVMValueRef func = LLVMAddFunction(c->module, f_name, f_type);

  if(!err)
  {
#if PONY_LLVM >= 309
    LLVM_DECLARE_ATTRIBUTEREF(nounwind_attr, nounwind, 0);

    LLVMAddAttributeAtIndex(func, LLVMAttributeFunctionIndex, nounwind_attr);
#else
    LLVMAddFunctionAttr(func, LLVMNoUnwindAttribute);
#endif
  }

  ponyint_pool_free_size(buf_size, f_params);
  return func;
}
Beispiel #16
0
LLVMValueRef gen_call(compile_t* c, ast_t* ast)
{
  // Special case calls.
  LLVMValueRef special;

  if(special_case_call(c, ast, &special))
    return special;

  AST_GET_CHILDREN(ast, positional, named, postfix);
  AST_GET_CHILDREN(postfix, receiver, method);
  ast_t* typeargs = NULL;

  // Dig through function qualification.
  switch(ast_id(receiver))
  {
    case TK_NEWREF:
    case TK_NEWBEREF:
    case TK_BEREF:
    case TK_FUNREF:
    case TK_BECHAIN:
    case TK_FUNCHAIN:
      typeargs = method;
      AST_GET_CHILDREN_NO_DECL(receiver, receiver, method);
      break;

    default: {}
  }

  // Get the receiver type.
  const char* method_name = ast_name(method);
  ast_t* type = ast_type(receiver);
  reach_type_t* t = reach_type(c->reach, type);
  pony_assert(t != NULL);

  // Generate the arguments.
  size_t count = ast_childcount(positional) + 1;
  size_t buf_size = count * sizeof(void*);

  LLVMValueRef* args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size);
  ast_t* arg = ast_child(positional);
  int i = 1;

  while(arg != NULL)
  {
    LLVMValueRef value = gen_expr(c, arg);

    if(value == NULL)
    {
      ponyint_pool_free_size(buf_size, args);
      return NULL;
    }

    args[i] = value;
    arg = ast_sibling(arg);
    i++;
  }

  bool is_new_call = false;

  // Generate the receiver. Must be done after the arguments because the args
  // could change things in the receiver expression that must be accounted for.
  if(call_needs_receiver(postfix, t))
  {
    switch(ast_id(postfix))
    {
      case TK_NEWREF:
      case TK_NEWBEREF:
      {
        call_tuple_indices_t tuple_indices = {NULL, 0, 4};
        tuple_indices.data =
          (size_t*)ponyint_pool_alloc_size(4 * sizeof(size_t));

        ast_t* current = ast;
        ast_t* parent = ast_parent(current);
        while((parent != NULL) && (ast_id(parent) != TK_ASSIGN) &&
          (ast_id(parent) != TK_CALL))
        {
          if(ast_id(parent) == TK_TUPLE)
          {
            size_t index = 0;
            ast_t* child = ast_child(parent);
            while(current != child)
            {
              ++index;
              child = ast_sibling(child);
            }
            tuple_indices_push(&tuple_indices, index);
          }
          current = parent;
          parent = ast_parent(current);
        }

        // If we're constructing an embed field, pass a pointer to the field
        // as the receiver. Otherwise, allocate an object.
        if((parent != NULL) && (ast_id(parent) == TK_ASSIGN))
        {
          size_t index = 1;
          current = ast_childidx(parent, 1);
          while((ast_id(current) == TK_TUPLE) || (ast_id(current) == TK_SEQ))
          {
            parent = current;
            if(ast_id(current) == TK_TUPLE)
            {
              // If there are no indices left, we're destructuring a tuple.
              // Errors in those cases have already been catched by the expr
              // pass.
              if(tuple_indices.count == 0)
                break;
              index = tuple_indices_pop(&tuple_indices);
              current = ast_childidx(parent, index);
            } else {
              current = ast_childlast(parent);
            }
          }
          if(ast_id(current) == TK_EMBEDREF)
          {
            args[0] = gen_fieldptr(c, current);
            set_descriptor(c, t, args[0]);
          } else {
            args[0] = gencall_alloc(c, t);
          }
        } else {
          args[0] = gencall_alloc(c, t);
        }
        is_new_call = true;
        ponyint_pool_free_size(tuple_indices.alloc * sizeof(size_t),
          tuple_indices.data);
        break;
      }

      case TK_BEREF:
      case TK_FUNREF:
      case TK_BECHAIN:
      case TK_FUNCHAIN:
        args[0] = gen_expr(c, receiver);
        break;

      default:
        pony_assert(0);
        return NULL;
    }
  } else {
    // Use a null for the receiver type.
    args[0] = LLVMConstNull(t->use_type);
  }

  // Static or virtual dispatch.
  token_id cap = cap_dispatch(type);
  reach_method_t* m = reach_method(t, cap, method_name, typeargs);
  LLVMValueRef func = dispatch_function(c, t, m, args[0]);

  bool is_message = false;

  if((ast_id(postfix) == TK_NEWBEREF) || (ast_id(postfix) == TK_BEREF) ||
    (ast_id(postfix) == TK_BECHAIN))
  {
    switch(t->underlying)
    {
      case TK_ACTOR:
        is_message = true;
        break;

      case TK_UNIONTYPE:
      case TK_ISECTTYPE:
      case TK_INTERFACE:
      case TK_TRAIT:
        if(m->cap == TK_TAG)
          is_message = can_inline_message_send(t, m, method_name);
        break;

      default: {}
    }
  }

  // Cast the arguments to the parameter types.
  LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func));
  LLVMTypeRef* params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
  LLVMGetParamTypes(f_type, params);

  arg = ast_child(positional);
  i = 1;

  LLVMValueRef r = NULL;

  if(is_message)
  {
    // If we're sending a message, trace and send here instead of calling the
    // sender to trace the most specific types possible.
    LLVMValueRef* cast_args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size);
    cast_args[0] = args[0];
    while(arg != NULL)
    {
      cast_args[i] = gen_assign_cast(c, params[i], args[i], ast_type(arg));
      arg = ast_sibling(arg);
      i++;
    }

    token_id cap = cap_dispatch(type);
    reach_method_t* m = reach_method(t, cap, method_name, typeargs);

    codegen_debugloc(c, ast);
    gen_send_message(c, m, args, cast_args, positional);
    codegen_debugloc(c, NULL);
    switch(ast_id(postfix))
    {
      case TK_NEWREF:
      case TK_NEWBEREF:
        r = args[0];
        break;

      default:
        r = c->none_instance;
        break;
    }
    ponyint_pool_free_size(buf_size, cast_args);
  } else {
    while(arg != NULL)
    {
      args[i] = gen_assign_cast(c, params[i], args[i], ast_type(arg));
      arg = ast_sibling(arg);
      i++;
    }

    if(func != NULL)
    {
      // If we can error out and we have an invoke target, generate an invoke
      // instead of a call.
      codegen_debugloc(c, ast);

      if(ast_canerror(ast) && (c->frame->invoke_target != NULL))
        r = invoke_fun(c, func, args, i, "", true);
      else
        r = codegen_call(c, func, args, i);

      if(is_new_call)
      {
        LLVMValueRef md = LLVMMDNodeInContext(c->context, NULL, 0);
        LLVMSetMetadataStr(r, "pony.newcall", md);
      }

      codegen_debugloc(c, NULL);
    }
  }

  // Class constructors return void, expression result is the receiver.
  if(((ast_id(postfix) == TK_NEWREF) || (ast_id(postfix) == TK_NEWBEREF)) &&
     (t->underlying == TK_CLASS))
    r = args[0];

  // Chained methods forward their receiver.
  if((ast_id(postfix) == TK_BECHAIN) || (ast_id(postfix) == TK_FUNCHAIN))
    r = args[0];

  ponyint_pool_free_size(buf_size, args);
  ponyint_pool_free_size(buf_size, params);
  return r;
}
Beispiel #17
0
bool expr_return(pass_opt_t* opt, ast_t* ast)
{
    typecheck_t* t = &opt->check;

    if(t->frame->method_body == NULL)
    {
        ast_error(ast, "return must occur in a method body");
        return false;
    }

    // return is always the last expression in a sequence
    assert(ast_sibling(ast) == NULL);

    if(ast_parent(ast) == t->frame->method_body)
    {
        ast_error(ast,
                  "use return only to exit early from a method, not at the end");
        return false;
    }

    ast_t* type = ast_childidx(t->frame->method, 4);
    ast_t* body = ast_child(ast);

    if(!coerce_literals(&body, type, opt))
        return false;

    ast_t* body_type = ast_type(body);

    if(is_typecheck_error(body_type))
        return false;

    if(is_control_type(body_type))
    {
        ast_error(body, "return value cannot be a control statement");
        return false;
    }

    bool ok = true;

    switch(ast_id(t->frame->method))
    {
    case TK_NEW:
        if(!is_none(body_type))
        {
            ast_error(ast, "return in a constructor must return None");
            ok = false;
        }
        break;

    case TK_BE:
        if(!is_none(body_type))
        {
            ast_error(ast, "return in a behaviour must return None");
            ok = false;
        }
        break;

    default:
    {
        // The body type must be a subtype of the return type, and an alias of
        // the body type must be a subtype of an alias of the return type.
        ast_t* a_type = alias(type);
        ast_t* a_body_type = alias(body_type);

        if(!is_subtype(body_type, type) || !is_subtype(a_body_type, a_type))
        {
            ast_t* last = ast_childlast(body);
            ast_error(last, "returned value isn't the return type");
            ast_error(type, "function return type: %s", ast_print_type(type));
            ast_error(body_type, "returned value type: %s",
                      ast_print_type(body_type));
            ok = false;
        }

        ast_free_unattached(a_type);
        ast_free_unattached(a_body_type);
    }
    }

    ast_settype(ast, ast_from(ast, TK_RETURN));
    ast_inheritflags(ast);
    return ok;
}
Beispiel #18
0
bool expr_seq(pass_opt_t* opt, ast_t* ast)
{
    bool ok = true;

    // Any expression other than the last that is still literal is an error
    for(ast_t* p = ast_child(ast); ast_sibling(p) != NULL; p = ast_sibling(p))
    {
        ast_t* p_type = ast_type(p);

        if(is_typecheck_error(p_type))
        {
            ok = false;
        } else if(is_type_literal(p_type)) {
            ast_error(p, "Cannot infer type of unused literal");
            ok = false;
        }
    }

    // We might already have a type due to a return expression.
    ast_t* type = ast_type(ast);
    ast_t* last = ast_childlast(ast);

    if((type != NULL) && !coerce_literals(&last, type, opt))
        return false;

    // Type is unioned with the type of the last child.
    type = control_type_add_branch(type, last);
    ast_settype(ast, type);
    ast_inheritflags(ast);

    if(!ast_has_scope(ast))
        return ok;

    ast_t* parent = ast_parent(ast);

    switch(ast_id(parent))
    {
    case TK_TRY:
    case TK_TRY_NO_CHECK:
    {
        // Propagate consumes forward in a try expression.
        AST_GET_CHILDREN(parent, body, else_clause, then_clause);

        if(body == ast)
        {
            // Push our consumes, but not defines, to the else clause.
            ast_inheritbranch(else_clause, body);
            ast_consolidate_branches(else_clause, 2);
        } else if(else_clause == ast) {
            // Push our consumes, but not defines, to the then clause. This
            // includes the consumes from the body.
            ast_inheritbranch(then_clause, else_clause);
            ast_consolidate_branches(then_clause, 2);
        }
    }

    default:
    {}
    }

    return ok;
}
Beispiel #19
0
bool expr_return(pass_opt_t* opt, ast_t* ast)
{
  typecheck_t* t = &opt->check;

  // return is always the last expression in a sequence
  assert(ast_sibling(ast) == NULL);

  if(ast_parent(ast) == t->frame->method_body)
  {
    ast_error(ast,
      "use return only to exit early from a method, not at the end");
    return false;
  }

  ast_t* type = ast_childidx(t->frame->method, 4);
  ast_t* body = ast_child(ast);

  if(!coerce_literals(&body, type, opt))
    return false;

  ast_t* body_type = ast_type(body);

  if(is_typecheck_error(body_type))
    return false;

  if(is_control_type(body_type))
  {
    ast_error(body, "return value cannot be a control statement");
    return false;
  }

  bool ok = true;

  switch(ast_id(t->frame->method))
  {
    case TK_NEW:
      if(is_this_incomplete(t, ast))
      {
        ast_error(ast,
          "all fields must be defined before constructor returns");
        ok = false;
      }
      break;

    case TK_BE:
      assert(is_none(body_type));
      break;

    default:
    {
      // The body type must be a subtype of the return type, and an alias of
      // the body type must be a subtype of an alias of the return type.
      ast_t* a_type = alias(type);
      ast_t* a_body_type = alias(body_type);

      errorframe_t info = NULL;
      if(!is_subtype(body_type, type, &info) ||
        !is_subtype(a_body_type, a_type, &info))
      {
        errorframe_t frame = NULL;
        ast_t* last = ast_childlast(body);
        ast_error_frame(&frame, last, "returned value isn't the return type");
        ast_error_frame(&frame, type, "function return type: %s",
          ast_print_type(type));
        ast_error_frame(&frame, body_type, "returned value type: %s",
          ast_print_type(body_type));
        errorframe_append(&frame, &info);
        errorframe_report(&frame);
        ok = false;
      }

      ast_free_unattached(a_type);
      ast_free_unattached(a_body_type);
    }
  }

  ast_settype(ast, ast_from(ast, TK_RETURN));
  ast_inheritflags(ast);
  return ok;
}
Beispiel #20
0
static LLVMValueRef declare_ffi(compile_t* c, const char* f_name,
  gentype_t* g, ast_t* args, bool err)
{
  ast_t* last_arg = ast_childlast(args);

  if((last_arg != NULL) && (ast_id(last_arg) == TK_ELLIPSIS))
    return declare_ffi_vararg(c, f_name, g, err);

  int count = (int)ast_childcount(args);
  size_t buf_size = count * sizeof(LLVMTypeRef);
  LLVMTypeRef* f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
  count = 0;

  ast_t* arg = ast_child(args);

  while(arg != NULL)
  {
    ast_t* p_type = ast_type(arg);

    if(p_type == NULL)
      p_type = ast_childidx(arg, 1);

    gentype_t param_g;

    if(!gentype(c, p_type, &param_g))
      return NULL;

    f_params[count++] = param_g.use_type;
    arg = ast_sibling(arg);
  }

  // We may have generated the function by generating a parameter type.
  LLVMValueRef func = LLVMGetNamedFunction(c->module, f_name);

  if(func == NULL)
  {
    LLVMTypeRef r_type;

    if(g->underlying == TK_TUPLETYPE)
    {
      // Can't use the named type. Build an unnamed type with the same
      // elements.
      unsigned int count = LLVMCountStructElementTypes(g->use_type);
      size_t buf_size = count * sizeof(LLVMTypeRef);
      LLVMTypeRef* e_types = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
      LLVMGetStructElementTypes(g->use_type, e_types);
      r_type = LLVMStructTypeInContext(c->context, e_types, count, false);
      ponyint_pool_free_size(buf_size, e_types);
    } else {
      r_type = g->use_type;
    }

    LLVMTypeRef f_type = LLVMFunctionType(r_type, f_params, count, false);
    func = LLVMAddFunction(c->module, f_name, f_type);

    if(!err)
      LLVMAddFunctionAttr(func, LLVMNoUnwindAttribute);
  }

  ponyint_pool_free_size(buf_size, f_params);
  return func;
}