Beispiel #1
0
LLVMValueRef gen_match(compile_t* c, ast_t* ast)
{
  bool needed = is_result_needed(ast);
  ast_t* type = ast_type(ast);
  AST_GET_CHILDREN(ast, match_expr, cases, else_expr);

  // We will have no type if all case have control types.
  LLVMTypeRef phi_type = NULL;

  if(needed && !is_control_type(type))
  {
    reach_type_t* t_phi = reach_type(c->reach, type);
    phi_type = t_phi->use_type;
  }

  ast_t* match_type = alias(ast_type(match_expr));
  LLVMValueRef match_value = gen_expr(c, match_expr);

  LLVMBasicBlockRef pattern_block = codegen_block(c, "case_pattern");
  LLVMBasicBlockRef else_block = codegen_block(c, "match_else");
  LLVMBasicBlockRef post_block = NULL;
  LLVMBasicBlockRef next_block = NULL;

  // Jump to the first case.
  LLVMBuildBr(c->builder, pattern_block);

  LLVMValueRef phi = GEN_NOVALUE;

  if(!is_control_type(type))
  {
    // Start the post block so that a case can modify the phi node.
    post_block = codegen_block(c, "match_post");
    LLVMPositionBuilderAtEnd(c->builder, post_block);

    if(needed)
      phi = LLVMBuildPhi(c->builder, phi_type, "");
    else
      phi = GEN_NOTNEEDED;
  }

  // Iterate over the cases.
  ast_t* the_case = ast_child(cases);

  while(the_case != NULL)
  {
    ast_t* next_case = ast_sibling(the_case);

    if(next_case != NULL)
      next_block = codegen_block(c, "case_pattern");
    else
      next_block = else_block;

    AST_GET_CHILDREN(the_case, pattern, guard, body);
    LLVMPositionBuilderAtEnd(c->builder, pattern_block);
    codegen_pushscope(c, the_case);

    ast_t* pattern_type = ast_type(the_case);
    bool ok = true;

    if(is_matchtype(match_type, pattern_type, c->opt) != MATCHTYPE_ACCEPT)
    {
      // If there's no possible match, jump directly to the next block.
      LLVMBuildBr(c->builder, next_block);
    } else {
      // Check the pattern.
      ok = static_match(c, match_value, match_type, pattern, next_block);

      // Check the guard.
      ok = ok && guard_match(c, guard, next_block);

      // Case body.
      ok = ok && case_body(c, body, post_block, phi, phi_type);
    }

    codegen_popscope(c);

    if(!ok)
    {
      ast_free_unattached(match_type);
      return NULL;
    }

    the_case = next_case;
    pattern_block = next_block;
  }

  ast_free_unattached(match_type);

  // Else body.
  LLVMPositionBuilderAtEnd(c->builder, else_block);
  codegen_pushscope(c, else_expr);
  bool ok = case_body(c, else_expr, post_block, phi, phi_type);
  codegen_popscope(c);

  if(!ok)
    return NULL;

  if(post_block != NULL)
    LLVMPositionBuilderAtEnd(c->builder, post_block);

  return phi;
}
Beispiel #2
0
bool literal_call(ast_t* ast, pass_opt_t* opt)
{
  pony_assert(ast != NULL);
  pony_assert(ast_id(ast) == TK_CALL);

  AST_GET_CHILDREN(ast, receiver, positional_args, named_args, question);

  ast_t* recv_type = ast_type(receiver);

  if(is_typecheck_error(recv_type))
    return false;

  if(ast_id(recv_type) == TK_LITERAL)
  {
    ast_error(opt->check.errors, ast, "Cannot call a literal");
    return false;
  }

  if(ast_id(recv_type) != TK_OPERATORLITERAL) // Nothing to do
    return true;

  lit_op_info_t const* op = (lit_op_info_t const*)ast_data(recv_type);
  pony_assert(op != NULL);

  if(ast_childcount(named_args) != 0)
  {
    ast_error(opt->check.errors, named_args, "Cannot use named arguments with literal operator");
    return false;
  }

  ast_t* arg = ast_child(positional_args);

  if(arg != NULL)
  {
    if(!unify(arg, opt, true))
      return false;

    ast_t* arg_type = ast_type(arg);

    if(is_typecheck_error(arg_type))
      return false;

    if(ast_id(arg_type) != TK_LITERAL)  // Apply argument type to receiver
      return coerce_literals(&receiver, arg_type, opt);

    if(!op->can_propogate_literal)
    {
      ast_error(opt->check.errors, ast, "Cannot infer operand type");
      return false;
    }
  }

  size_t arg_count = ast_childcount(positional_args);

  if(op->arg_count != arg_count)
  {
    ast_error(opt->check.errors, ast, "Invalid number of arguments to literal operator");
    return false;
  }

  make_literal_type(ast);
  return true;
}
Beispiel #3
0
LLVMValueRef gen_ffi(compile_t* c, ast_t* ast)
{
  AST_GET_CHILDREN(ast, id, typeargs, args, named_args, can_err);
  bool err = (ast_id(can_err) == TK_QUESTION);

  // Get the function name, +1 to skip leading @
  const char* f_name = ast_name(id) + 1;

  // Generate the return type.
  ast_t* type = ast_type(ast);
  gentype_t g;

  // Emit dwarf location of ffi call
  dwarf_location(&c->dwarf, ast);

  if(!gentype(c, type, &g))
    return NULL;

  // Get the function.
  LLVMValueRef func = LLVMGetNamedFunction(c->module, f_name);

  if(func == NULL)
  {
    // If we have no prototype, declare one.
    ast_t* decl = (ast_t*)ast_data(ast);

    if(decl != NULL)
    {
      // Define using the declared types.
      AST_GET_CHILDREN(decl, decl_id, decl_ret, decl_params, decl_err);
      err = (ast_id(decl_err) == TK_QUESTION);
      func = declare_ffi(c, f_name, &g, decl_params, err);
    } else if(!strncmp(f_name, "llvm.", 5)) {
      // Intrinsic, so use the exact types we supply.
      func = declare_ffi(c, f_name, &g, args, err);
    } else {
      // Make it varargs.
      func = declare_ffi_vararg(c, f_name, &g, err);
    }
  }

  // Generate the arguments.
  int count = (int)ast_childcount(args);
  size_t buf_size = count * sizeof(LLVMValueRef);
  LLVMValueRef* f_args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size);

  LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func));
  LLVMTypeRef* f_params = NULL;
  bool vararg = (LLVMIsFunctionVarArg(f_type) != 0);

  if(!vararg)
  {
    f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
    LLVMGetParamTypes(f_type, f_params);
  }

  ast_t* arg = ast_child(args);

  for(int i = 0; i < count; i++)
  {
    f_args[i] = gen_expr(c, arg);

    if(!vararg && (LLVMGetTypeKind(f_params[i]) == LLVMPointerTypeKind))
    {
      if(LLVMGetTypeKind(LLVMTypeOf(f_args[i])) == LLVMIntegerTypeKind)
        f_args[i] = LLVMBuildIntToPtr(c->builder, f_args[i], f_params[i], "");
      else
        f_args[i] = LLVMBuildBitCast(c->builder, f_args[i], f_params[i], "");
    }

    if(f_args[i] == NULL)
    {
      ponyint_pool_free_size(buf_size, f_args);
      return NULL;
    }

    arg = ast_sibling(arg);
  }

  // If we can error out and we have an invoke target, generate an invoke
  // instead of a call.
  LLVMValueRef result;

  if(err && (c->frame->invoke_target != NULL))
    result = invoke_fun(c, func, f_args, count, "", false);
  else
    result = LLVMBuildCall(c->builder, func, f_args, count, "");

  ponyint_pool_free_size(buf_size, f_args);

  if(!vararg)
    ponyint_pool_free_size(buf_size, f_params);

  // Special case a None return value, which is used for void functions.
  if(is_none(type))
    return g.instance;

  return result;
}
Beispiel #4
0
static bool constructor_type(ast_t* ast, token_id cap, ast_t* type,
  ast_t** resultp)
{
  switch(ast_id(type))
  {
    case TK_NOMINAL:
    {
      ast_t* def = (ast_t*)ast_data(type);

      switch(ast_id(def))
      {
        case TK_PRIMITIVE:
        case TK_CLASS:
          ast_setid(ast, TK_NEWREF);
          break;

        case TK_ACTOR:
          ast_setid(ast, TK_NEWBEREF);
          break;

        case TK_TYPE:
          ast_error(ast, "can't call a constructor on a type alias: %s",
            ast_print_type(type));
          return false;

        case TK_INTERFACE:
          ast_error(ast, "can't call a constructor on an interface: %s",
            ast_print_type(type));
          return false;

        case TK_TRAIT:
          ast_error(ast, "can't call a constructor on a trait: %s",
            ast_print_type(type));
          return false;

        default:
          assert(0);
          return false;
      }
      return true;
    }

    case TK_TYPEPARAMREF:
    {
      // Alter the return type of the method.
      type = ast_dup(type);

      AST_GET_CHILDREN(type, tid, tcap, teph);
      ast_setid(tcap, cap);
      ast_setid(teph, TK_EPHEMERAL);
      ast_replace(resultp, type);

      // This could this be an actor.
      ast_setid(ast, TK_NEWBEREF);
      return true;
    }

    case TK_ARROW:
    {
      AST_GET_CHILDREN(type, left, right);
      return constructor_type(ast, cap, right, resultp);
    }

    default: {}
  }

  assert(0);
  return false;
}
Beispiel #5
0
bool expr_try(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, body, else_clause, then_clause);

  ast_t* body_type = ast_type(body);
  ast_t* else_type = ast_type(else_clause);
  ast_t* then_type = ast_type(then_clause);

  if(is_typecheck_error(body_type) ||
    is_typecheck_error(else_type) ||
    is_typecheck_error(then_type))
    return false;

  // It has to be possible for the left side to result in an error.
  if((ast_id(ast) == TK_TRY) && !ast_canerror(body))
  {
    ast_error(body, "try expression never results in an error");
    return false;
  }

  ast_t* type = NULL;

  if(!is_control_type(body_type))
    type = control_type_add_branch(type, body);

  if(!is_control_type(else_type))
    type = control_type_add_branch(type, else_clause);

  if(type == NULL)
  {
    if(ast_sibling(ast) != NULL)
    {
      ast_error(ast_sibling(ast), "unreachable code");
      return false;
    }

    type = ast_from(ast, TK_TRY);
  }

  // The then clause does not affect the type of the expression.
  if(is_control_type(then_type))
  {
    ast_error(then_clause, "then clause always terminates the function");
    return false;
  }

  if(is_type_literal(then_type))
  {
    ast_error(then_clause, "Cannot infer type of unused literal");
    return false;
  }

  ast_settype(ast, type);

  // Doesn't inherit error from the body.
  if(ast_canerror(else_clause) || ast_canerror(then_clause))
    ast_seterror(ast);

  if(ast_cansend(body) || ast_cansend(else_clause) || ast_cansend(then_clause))
    ast_setsend(ast);

  if(ast_mightsend(body) || ast_mightsend(else_clause) ||
    ast_mightsend(then_clause))
    ast_setmightsend(ast);

  literal_unify_control(ast, opt);

  // Push the symbol status from the then clause to our parent scope.
  ast_inheritstatus(ast_parent(ast), then_clause);
  return true;
}
Beispiel #6
0
static bool is_valid_pattern(pass_opt_t* opt, ast_t* pattern)
{
  if(ast_id(pattern) == TK_NONE)
  {
    ast_settype(pattern, ast_from(pattern, TK_DONTCARE));
    return true;
  }

  ast_t* pattern_type = ast_type(pattern);

  if(is_control_type(pattern_type))
  {
    ast_error(pattern, "not a matchable pattern");
    return false;
  }

  switch(ast_id(pattern))
  {
    case TK_VAR:
    case TK_LET:
    {
      // Disallow capturing tuples.
      AST_GET_CHILDREN(pattern, id, capture_type);

      if(ast_id(capture_type) == TK_TUPLETYPE)
      {
        ast_error(capture_type,
          "can't capture a tuple, change this into a tuple of capture "
          "expressions");

        return false;
      }

      // Set the pattern type to be the capture type.
      ast_settype(pattern, capture_type);
      return true;
    }

    case TK_TUPLE:
    {
      ast_t* pattern_child = ast_child(pattern);

      // Treat a one element tuple as a normal expression.
      if(ast_sibling(pattern_child) == NULL)
      {
        bool ok = is_valid_pattern(opt, pattern_child);
        ast_settype(pattern, ast_type(pattern_child));
        return ok;
      }

      // Check every element pairwise.
      ast_t* pattern_type = ast_from(pattern, TK_TUPLETYPE);
      bool ok = true;

      while(pattern_child != NULL)
      {
        if(!is_valid_pattern(opt, pattern_child))
          ok = false;

        ast_append(pattern_type, ast_type(pattern_child));
        pattern_child = ast_sibling(pattern_child);
      }

      ast_settype(pattern, pattern_type);
      return ok;
    }

    case TK_SEQ:
    {
      // Patterns cannot contain sequences.
      ast_t* child = ast_child(pattern);
      ast_t* next = ast_sibling(child);

      if(next != NULL)
      {
        ast_error(next, "expression in patterns cannot be sequences");
        return false;
      }

      bool ok = is_valid_pattern(opt, child);
      ast_settype(pattern, ast_type(child));
      return ok;
    }

    case TK_DONTCARE:
      // It's always ok not to care.
      return true;

    default:
    {
      // Structural equality, pattern.eq(match).
      ast_t* fun = lookup(opt, pattern, pattern_type, stringtab("eq"));

      if(fun == NULL)
      {
        ast_error(pattern,
          "this pattern element doesn't support structural equality");

        return false;
      }

      if(ast_id(fun) != TK_FUN)
      {
        ast_error(pattern, "eq is not a function on this pattern element");
        ast_error(fun, "definition of eq is here");
        ast_free_unattached(fun);
        return false;
      }

      AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, partial);
      bool ok = true;

      if(ast_id(typeparams) != TK_NONE)
      {
        ast_error(pattern, "polymorphic eq not supported in pattern matching");
        ok = false;
      }

      if(!is_bool(result))
      {
        ast_error(pattern, "eq must return Bool when pattern matching");
        ok = false;
      }

      if(ast_id(partial) != TK_NONE)
      {
        ast_error(pattern, "eq cannot be partial when pattern matching");
        ok = false;
      }

      ast_t* param = ast_child(params);

      if(param == NULL || ast_sibling(param) != NULL)
      {
        ast_error(pattern,
          "eq must take a single argument when pattern matching");

        ok = false;
      } else {
        AST_GET_CHILDREN(param, param_id, param_type);
        ast_settype(pattern, param_type);
      }

      ast_free_unattached(fun);
      return ok;
    }
  }

  assert(0);
  return false;
}
Beispiel #7
0
bool expr_case(pass_opt_t* opt, ast_t* ast)
{
  assert(opt != NULL);
  assert(ast_id(ast) == TK_CASE);
  AST_GET_CHILDREN(ast, pattern, guard, body);

  if((ast_id(pattern) == TK_NONE) && (ast_id(guard) == TK_NONE))
  {
    ast_error(ast, "can't have a case with no conditions, use an else clause");
    return false;
  }

  ast_t* cases = ast_parent(ast);
  ast_t* match = ast_parent(cases);
  ast_t* match_expr = ast_child(match);
  ast_t* match_type = ast_type(match_expr);

  if(is_control_type(match_type) || is_typecheck_error(match_type))
    return false;

  if(!infer_pattern_type(pattern, match_type, opt))
    return false;

  if(!is_valid_pattern(opt, pattern))
    return false;

  ast_t* operand_type = alias(match_type);
  ast_t* pattern_type = ast_type(pattern);
  bool ok = true;

  switch(is_matchtype(operand_type, pattern_type))
  {
    case MATCHTYPE_ACCEPT:
      break;

    case MATCHTYPE_REJECT:
      ast_error(pattern, "this pattern can never match");
      ast_error(match_type, "match type: %s", ast_print_type(operand_type));
      ast_error(pattern, "pattern type: %s", ast_print_type(pattern_type));
      ok = false;
      break;

    case MATCHTYPE_DENY:
      ast_error(pattern, "this capture violates capabilities");
      ast_error(match_type, "match type: %s", ast_print_type(operand_type));
      ast_error(pattern, "pattern type: %s", ast_print_type(pattern_type));
      ok = false;
      break;
  }

  if(ast_id(guard) != TK_NONE)
  {
    ast_t* guard_type = ast_type(guard);

    if(is_typecheck_error(guard_type))
    {
      ok = false;
    }
    else if(!is_bool(guard_type))
    {
      ast_error(guard, "guard must be a boolean expression");
      ok = false;
    }
  }

  ast_free_unattached(operand_type);
  ast_inheritflags(ast);
  return ok;
}
Beispiel #8
0
static bool special_case_operator(compile_t* c, ast_t* ast,
  LLVMValueRef *value, bool short_circuit, bool native128)
{
  AST_GET_CHILDREN(ast, postfix, positional, named, question);
  AST_GET_CHILDREN(postfix, left, method);

  ast_t* right = ast_child(positional);
  const char* name = ast_name(method);
  bool special_case = true;
  *value = NULL;

  codegen_debugloc(c, ast);

  if(name == c->str_add)
    *value = gen_add(c, left, right, true);
  else if(name == c->str_sub)
    *value = gen_sub(c, left, right, true);
  else if((name == c->str_mul) && native128)
    *value = gen_mul(c, left, right, true);
  else if((name == c->str_div) && native128)
    *value = gen_div(c, left, right, true);
  else if((name == c->str_rem) && native128)
    *value = gen_rem(c, left, right, true);
  else if(name == c->str_neg)
    *value = gen_neg(c, left, true);
  else if(name == c->str_add_unsafe)
    *value = gen_add(c, left, right, false);
  else if(name == c->str_sub_unsafe)
    *value = gen_sub(c, left, right, false);
  else if((name == c->str_mul_unsafe) && native128)
    *value = gen_mul(c, left, right, false);
  else if((name == c->str_div_unsafe) && native128)
    *value = gen_div(c, left, right, false);
  else if((name == c->str_rem_unsafe) && native128)
    *value = gen_rem(c, left, right, false);
  else if(name == c->str_neg_unsafe)
    *value = gen_neg(c, left, false);
  else if((name == c->str_and) && short_circuit)
    *value = gen_and_sc(c, left, right);
  else if((name == c->str_or) && short_circuit)
    *value = gen_or_sc(c, left, right);
  else if((name == c->str_and) && !short_circuit)
    *value = gen_and(c, left, right);
  else if((name == c->str_or) && !short_circuit)
    *value = gen_or(c, left, right);
  else if(name == c->str_xor)
    *value = gen_xor(c, left, right);
  else if(name == c->str_not)
    *value = gen_not(c, left);
  else if(name == c->str_shl)
    *value = gen_shl(c, left, right, true);
  else if(name == c->str_shr)
    *value = gen_shr(c, left, right, true);
  else if(name == c->str_shl_unsafe)
    *value = gen_shl(c, left, right, false);
  else if(name == c->str_shr_unsafe)
    *value = gen_shr(c, left, right, false);
  else if(name == c->str_eq)
    *value = gen_eq(c, left, right, true);
  else if(name == c->str_ne)
    *value = gen_ne(c, left, right, true);
  else if(name == c->str_lt)
    *value = gen_lt(c, left, right, true);
  else if(name == c->str_le)
    *value = gen_le(c, left, right, true);
  else if(name == c->str_ge)
    *value = gen_ge(c, left, right, true);
  else if(name == c->str_gt)
    *value = gen_gt(c, left, right, true);
  else if(name == c->str_eq_unsafe)
    *value = gen_eq(c, left, right, false);
  else if(name == c->str_ne_unsafe)
    *value = gen_ne(c, left, right, false);
  else if(name == c->str_lt_unsafe)
    *value = gen_lt(c, left, right, false);
  else if(name == c->str_le_unsafe)
    *value = gen_le(c, left, right, false);
  else if(name == c->str_ge_unsafe)
    *value = gen_ge(c, left, right, false);
  else if(name == c->str_gt_unsafe)
    *value = gen_gt(c, left, right, false);
  else
    special_case = false;

  codegen_debugloc(c, NULL);
  return special_case;
}
Beispiel #9
0
LLVMValueRef gen_ffi(compile_t* c, ast_t* ast)
{
  AST_GET_CHILDREN(ast, id, typeargs, args, named_args, can_err);
  bool err = (ast_id(can_err) == TK_QUESTION);

  // Get the function name, +1 to skip leading @
  const char* f_name = ast_name(id) + 1;

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

  // Get the return type.
  ast_t* type = deferred_reify(reify, ast_type(ast), c->opt);
  reach_type_t* t = reach_type(c->reach, type);
  pony_assert(t != NULL);
  ast_free_unattached(type);

  // Get the function. First check if the name is in use by a global and error
  // if it's the case.
  ffi_decl_t* ffi_decl;
  bool is_func = false;
  LLVMValueRef func = LLVMGetNamedGlobal(c->module, f_name);

  if(func == NULL)
  {
    func = LLVMGetNamedFunction(c->module, f_name);
    is_func = true;
  }

  if(func == NULL)
  {
    // If we have no prototype, declare one.
    ast_t* decl = (ast_t*)ast_data(ast);

    if(decl != NULL)
    {
      // Define using the declared types.
      AST_GET_CHILDREN(decl, decl_id, decl_ret, decl_params, decl_err);
      err = (ast_id(decl_err) == TK_QUESTION);
      func = declare_ffi(c, f_name, t, decl_params, false);
    } else if(!strncmp(f_name, "llvm.", 5) || !strncmp(f_name, "internal.", 9)) {
      // Intrinsic, so use the exact types we supply.
      func = declare_ffi(c, f_name, t, args, true);
    } else {
      // Make it varargs.
      func = declare_ffi_vararg(c, f_name, t);
    }

    size_t index = HASHMAP_UNKNOWN;

#ifndef PONY_NDEBUG
    ffi_decl_t k;
    k.func = func;

    ffi_decl = ffi_decls_get(&c->ffi_decls, &k, &index);
    pony_assert(ffi_decl == NULL);
#endif

    ffi_decl = POOL_ALLOC(ffi_decl_t);
    ffi_decl->func = func;
    ffi_decl->decl = (decl != NULL) ? decl : ast;

    ffi_decls_putindex(&c->ffi_decls, ffi_decl, index);
  } else {
    ffi_decl_t k;
    k.func = func;
    size_t index = HASHMAP_UNKNOWN;

    ffi_decl = ffi_decls_get(&c->ffi_decls, &k, &index);

    if((ffi_decl == NULL) && (!is_func || LLVMHasMetadataStr(func, "pony.abi")))
    {
      ast_error(c->opt->check.errors, ast, "cannot use '%s' as an FFI name: "
        "name is already in use by the internal ABI", f_name);
      return NULL;
    }

    pony_assert(is_func);
  }

  // Generate the arguments.
  int count = (int)ast_childcount(args);
  size_t buf_size = count * sizeof(LLVMValueRef);
  LLVMValueRef* f_args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size);

  LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func));
  LLVMTypeRef* f_params = NULL;
  bool vararg = (LLVMIsFunctionVarArg(f_type) != 0);

  if(!vararg)
  {
    if(count != (int)LLVMCountParamTypes(f_type))
    {
      ast_error(c->opt->check.errors, ast,
        "conflicting declarations for FFI function: declarations have an "
        "incompatible number of parameters");

      if(ffi_decl != NULL)
        ast_error_continue(c->opt->check.errors, ffi_decl->decl, "first "
          "declaration is here");

      return NULL;
    }

    f_params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
    LLVMGetParamTypes(f_type, f_params);
  }

  ast_t* arg = ast_child(args);

  for(int i = 0; i < count; i++)
  {
    f_args[i] = gen_expr(c, arg);

    if(!vararg)
      f_args[i] = cast_ffi_arg(c, ffi_decl, ast, f_args[i], f_params[i],
        "parameters");

    if(f_args[i] == NULL)
    {
      ponyint_pool_free_size(buf_size, f_args);
      return NULL;
    }

    arg = ast_sibling(arg);
  }

  // If we can error out and we have an invoke target, generate an invoke
  // instead of a call.
  LLVMValueRef result;
  codegen_debugloc(c, ast);

  if(err && (c->frame->invoke_target != NULL))
    result = invoke_fun(c, func, f_args, count, "", false);
  else
    result = LLVMBuildCall(c->builder, func, f_args, count, "");

  codegen_debugloc(c, NULL);
  ponyint_pool_free_size(buf_size, f_args);

  if(!vararg)
    ponyint_pool_free_size(buf_size, f_params);

  compile_type_t* c_t = (compile_type_t*)t->c_type;

  // Special case a None return value, which is used for void functions.
  bool isnone = is_none(t->ast);
  bool isvoid = LLVMGetReturnType(f_type) == c->void_type;

  if(isnone && isvoid)
  {
    result = c_t->instance;
  } else if(isnone != isvoid) {
    report_ffi_type_err(c, ffi_decl, ast, "return values");
    return NULL;
  }

  result = cast_ffi_arg(c, ffi_decl, ast, result, c_t->use_type,
    "return values");
  result = gen_assign_cast(c, c_t->use_type, result, t->ast_cap);

  return result;
}
Beispiel #10
0
static bool is_lvalue(typecheck_t* t, ast_t* ast, bool need_value)
{
  switch(ast_id(ast))
  {
    case TK_DONTCARE:
      // Can only assign to it if we don't need the value.
      return !need_value;

    case TK_VAR:
    case TK_LET:
      return assign_id(t, ast_child(ast), ast_id(ast) == TK_LET, need_value);

    case TK_VARREF:
    {
      ast_t* id = ast_child(ast);
      return assign_id(t, id, false, need_value);
    }

    case TK_LETREF:
    {
      ast_error(ast, "can't assign to a let local");
      return false;
    }

    case TK_FVARREF:
    {
      AST_GET_CHILDREN(ast, left, right);

      if(ast_id(left) == TK_THIS)
        return assign_id(t, right, false, need_value);

      return true;
    }

    case TK_FLETREF:
    {
      AST_GET_CHILDREN(ast, left, right);

      if(ast_id(left) != TK_THIS)
      {
        ast_error(ast, "can't assign to a let field");
        return false;
      }

      if(t->frame->loop_body != NULL)
      {
        ast_error(ast, "can't assign to a let field in a loop");
        return false;
      }

      return assign_id(t, right, true, need_value);
    }

    case TK_EMBEDREF:
    {
      AST_GET_CHILDREN(ast, left, right);

      if(ast_id(left) != TK_THIS)
      {
        ast_error(ast, "can't assign to an embed field");
        return false;
      }

      if(t->frame->loop_body != NULL)
      {
        ast_error(ast, "can't assign to an embed field in a loop");
        return false;
      }

      return assign_id(t, right, true, need_value);
    }

    case TK_TUPLE:
    {
      // A tuple is an lvalue if every component expression is an lvalue.
      ast_t* child = ast_child(ast);

      while(child != NULL)
      {
        if(!is_lvalue(t, child, need_value))
          return false;

        child = ast_sibling(child);
      }

      return true;
    }

    case TK_SEQ:
    {
      // A sequence is an lvalue if it has a single child that is an lvalue.
      // This is used because the components of a tuple are sequences.
      ast_t* child = ast_child(ast);

      if(ast_sibling(child) != NULL)
        return false;

      return is_lvalue(t, child, need_value);
    }

    default: {}
  }

  return false;
}
Beispiel #11
0
bool safe_to_write(ast_t* ast, ast_t* type)
{
  switch(ast_id(ast))
  {
    case TK_VAR:
    case TK_LET:
    case TK_VARREF:
    case TK_DONTCARE:
      return true;

    case TK_FVARREF:
    case TK_FLETREF:
    case TK_EMBEDREF:
    {
      // If the ast is x.f, we need the type of x, which will be a nominal
      // type or an arrow type, since we were able to lookup a field on it.
      AST_GET_CHILDREN(ast, left, right);
      ast_t* l_type = ast_type(left);

      // Any viewpoint adapted type will not be safe to write to.
      if(ast_id(l_type) != TK_NOMINAL)
        return false;

      token_id l_cap = cap_single(l_type);

      // If the RHS is safe to write, we're done.
      if(safe_field_write(l_cap, type))
        return true;

      // If the field type (without adaptation) is safe, then it's ok as
      // well. So iso.tag = ref should be allowed.
      ast_t* r_type = ast_type(right);
      return safe_field_write(l_cap, r_type);
    }

    case TK_TUPLE:
    {
      // At this point, we know these will be the same length.
      assert(ast_id(type) == TK_TUPLETYPE);
      ast_t* child = ast_child(ast);
      ast_t* type_child = ast_child(type);

      while(child != NULL)
      {
        if(!safe_to_write(child, type_child))
          return false;

        child = ast_sibling(child);
        type_child = ast_sibling(type_child);
      }

      assert(type_child == NULL);
      return true;
    }

    case TK_SEQ:
    {
      // Occurs when there is a tuple on the left. Each child of the tuple will
      // be a sequence, but only sequences with a single writeable child are
      // valid. Other types won't appear here.
      return safe_to_write(ast_child(ast), type);
    }

    default: {}
  }

  assert(0);
  return false;
}
Beispiel #12
0
bool expr_assign(pass_opt_t* opt, ast_t* ast)
{
  // Left and right are swapped in the AST to make sure we type check the
  // right side before the left. Fetch them in the opposite order.
  assert(ast != NULL);

  AST_GET_CHILDREN(ast, right, left);
  ast_t* l_type = ast_type(left);

  if(!is_lvalue(&opt->check, left, is_result_needed(ast)))
  {
    ast_error(ast, "left side must be something that can be assigned to");
    return false;
  }

  assert(l_type != NULL);

  if(!coerce_literals(&right, l_type, opt))
    return false;

  ast_t* r_type = ast_type(right);

  if(is_typecheck_error(r_type))
    return false;

  if(!infer_locals(left, r_type))
    return false;

  // Inferring locals may have changed the left type.
  l_type = ast_type(left);

  // Assignment is based on the alias of the right hand side.
  ast_t* a_type = alias(r_type);

  if(!is_subtype(a_type, l_type, true))
  {
    ast_error(ast, "right side must be a subtype of left side");
    ast_error(a_type, "right side type: %s", ast_print_type(a_type));
    ast_error(l_type, "left side type: %s", ast_print_type(l_type));
    ast_free_unattached(a_type);
    return false;
  }

  if((ast_id(left) == TK_TUPLE) && (ast_id(a_type) != TK_TUPLETYPE))
  {
    switch(ast_id(a_type))
    {
      case TK_UNIONTYPE:
        ast_error(ast,
          "can't destructure a union using assignment, use pattern matching "
          "instead");
        break;

      case TK_ISECTTYPE:
        ast_error(ast,
          "can't destructure an intersection using assignment, use pattern "
          "matching instead");
        break;

      default:
        assert(0);
        break;
    }

    ast_error(a_type, "right side type: %s", ast_print_type(a_type));
    ast_free_unattached(a_type);
    return false;
  }

  bool ok_safe = safe_to_write(left, a_type);

  if(!ok_safe)
  {
    if(ast_id(left) == TK_FVARREF && ast_child(left) != NULL &&
      ast_id(ast_child(left)) == TK_THIS)
    {
      // We are writing to a field in this
      ast_t* fn = ast_nearest(left, TK_FUN);

      if(fn != NULL)
      {
        ast_t* iso = ast_child(fn);
        assert(iso != NULL);
        token_id iso_id = ast_id(iso);

        if(iso_id == TK_BOX || iso_id == TK_VAL || iso_id == TK_TAG)
        {
          ast_error(ast, "cannot write to a field in a %s function. If you are trying to change state in a function use fun ref",
            lexer_print(iso_id));
          ast_free_unattached(a_type);
          return false;
        }
      }
    }

    ast_error(ast, "not safe to write right side to left side");
    ast_error(a_type, "right side type: %s", ast_print_type(a_type));
    ast_free_unattached(a_type);
    return false;
  }

  ast_free_unattached(a_type);

  // If it's an embedded field, check for a constructor result.
  if(ast_id(left) == TK_EMBEDREF)
  {
    if((ast_id(right) != TK_CALL) ||
      (ast_id(ast_childidx(right, 2)) != TK_NEWREF))
    {
      ast_error(ast, "an embedded field must be assigned using a constructor");
      return false;
    }
  }

  ast_settype(ast, consume_type(l_type, TK_NONE));
  ast_inheritflags(ast);
  return true;
}
Beispiel #13
0
// Resolve the field delegate body to use for the given method, if any.
// Return the body to use, NULL if none found or BODY_ERROR on error.
static ast_t* resolve_delegate_body(ast_t* entity, ast_t* method,
  method_t* info, const char* name)
{
  assert(entity != NULL);
  assert(method != NULL);
  assert(info != NULL);
  assert(name != NULL);

  if(info->delegate_field_2 != NULL)
  {
    // Ambiguous delegate
    assert(info->delegate_field_1 != NULL);
    assert(info->delegate_target_1 != NULL);
    assert(info->delegate_target_2 != NULL);

    ast_error(entity,
      "clashing delegates for method %s, local disambiguation required", name);
    ast_error(info->delegate_field_1, "field %s delegates to %s via %s",
      ast_name(ast_child(info->delegate_field_1)), name,
      ast_name(ast_child(info->delegate_target_1)));
    ast_error(info->delegate_field_2, "field %s delegates to %s via %s",
      ast_name(ast_child(info->delegate_field_2)), name,
      ast_name(ast_child(info->delegate_target_2)));

    return BODY_ERROR;
  }

  if(info->delegate_field_1 == NULL)  // No delegation needed
    return NULL;

  // We have a delegation, make a redirection body
  const char* field_name = ast_name(ast_child(info->delegate_field_1));
  ast_t* args = ast_from(info->delegate_field_1, TK_NONE);
  ast_t* last_arg = NULL;

  AST_GET_CHILDREN(method, cap, id, t_params, params, result, error, old_body);

  for(ast_t* p = ast_child(params); p != NULL; p = ast_sibling(p))
  {
    const char* param_name = ast_name(ast_child(p));

    BUILD(arg, info->delegate_field_1,
      NODE(TK_SEQ,
        NODE(TK_CONSUME,
          NONE
          NODE(TK_REFERENCE, ID(param_name)))));

    ast_list_append(args, &last_arg, arg);
    ast_setid(args, TK_POSITIONALARGS);
  }

  BUILD(body, info->delegate_field_1,
    NODE(TK_SEQ,
      NODE(TK_CALL,
        TREE(args)    // Positional args
        NODE(TK_NONE) // Named args
        NODE(TK_DOT,  // Receiver
          NODE(TK_REFERENCE, ID(field_name))
          ID(name)))));

  if(is_none(result))
  {
    // Add None to end of body. Whilst the call generated above will return
    // None anyway in this case, without this extra None testing is very hard
    // since a directly written version of this body will have the None.
    BUILD(none, info->delegate_field_1,
      NODE(TK_REFERENCE, ID("None")));

    ast_append(body, none);
  }

  info->body_donor = entity;
  return body;
}
Beispiel #14
0
// Process all field delegations in the given type.
// Stage 3.
static bool field_delegations(ast_t* entity)
{
  assert(entity != NULL);

  ast_t* members = ast_childidx(entity, 4);
  assert(members != NULL);

  bool r = true;

  // Check all fields
  for(ast_t* f = ast_child(members); f != NULL; f = ast_sibling(f))
  {
    if(is_field(f))
    {
      AST_GET_CHILDREN(f, id, f_type, value, delegates);

      // Check all delegates for field
      for(ast_t* d = ast_child(delegates); d != NULL; d = ast_sibling(d))
      {
        if(!check_delegate(entity, f_type, d))
        {
          r = false;
          continue;
        }

        // Mark all methods in delegate trait as targets for this field
        ast_t* trait = (ast_t*)ast_data(d);
        assert(trait != NULL);
        ast_t* t_members = ast_childidx(trait, 4);

        for(ast_t* m = ast_child(t_members); m != NULL; m = ast_sibling(m))
        {
          if(is_method(m))
          {
            // Mark method as delegate target for this field
            const char* method_name = ast_name(ast_childidx(m, 1));
            assert(method_name != NULL);

            ast_t* local_method = ast_get(entity, method_name, NULL);
            assert(local_method != NULL);

            method_t* info = (method_t*)ast_data(local_method);
            assert(info != NULL);

            if(info->delegate_field_1 == NULL)
            {
              // First delegate field for this method
              info->delegate_field_1 = f;
              info->delegate_target_1 = d;
            }
            else if(info->delegate_field_2 == NULL &&
              info->delegate_field_1 != f)
            {
              // We already have one delegate field, record second
              info->delegate_field_2 = f;
              info->delegate_target_2 = d;
            }
          }
        }
      }
    }
  }

  return r;
}
Beispiel #15
0
LLVMValueRef gen_if(compile_t* c, ast_t* ast)
{
  bool needed = is_result_needed(ast);
  ast_t* type = ast_type(ast);
  AST_GET_CHILDREN(ast, cond, left, right);

  ast_t* left_type = ast_type(left);
  ast_t* right_type = ast_type(right);

  // We will have no type if both branches have return statements.
  reach_type_t* phi_type = NULL;

  if(!is_control_type(type))
    phi_type = reach_type(c->reach, type);

  LLVMValueRef c_value = gen_expr(c, cond);

  if(c_value == NULL)
    return NULL;

  // If the conditional is constant, generate only one branch.
  bool gen_left = true;
  bool gen_right = true;

  if(LLVMIsAConstantInt(c_value))
  {
    int value = (int)LLVMConstIntGetZExtValue(c_value);

    if(value == 0)
      gen_left = false;
    else
      gen_right = false;
  }

  LLVMBasicBlockRef then_block = codegen_block(c, "if_then");
  LLVMBasicBlockRef else_block = codegen_block(c, "if_else");
  LLVMBasicBlockRef post_block = NULL;

  // If both branches return, we have no post block.
  if(!is_control_type(type))
    post_block = codegen_block(c, "if_post");

  LLVMValueRef test = LLVMBuildTrunc(c->builder, c_value, c->i1, "");
  LLVMBuildCondBr(c->builder, test, then_block, else_block);

  // Left branch.
  LLVMPositionBuilderAtEnd(c->builder, then_block);
  LLVMValueRef l_value;

  if(gen_left)
  {
    l_value = gen_expr(c, left);
  } else if(phi_type != NULL) {
    l_value = LLVMConstNull(phi_type->use_type);
  } else {
    LLVMBuildUnreachable(c->builder);
    l_value = GEN_NOVALUE;
  }

  if(l_value != GEN_NOVALUE)
  {
    if(needed)
      l_value = gen_assign_cast(c, phi_type->use_type, l_value, left_type);

    if(l_value == NULL)
      return NULL;

    then_block = LLVMGetInsertBlock(c->builder);
    LLVMBuildBr(c->builder, post_block);
  }

  // Right branch.
  LLVMPositionBuilderAtEnd(c->builder, else_block);
  LLVMValueRef r_value;

  if(gen_right)
  {
    r_value = gen_expr(c, right);
  } else if(phi_type != NULL) {
    r_value = LLVMConstNull(phi_type->use_type);
  } else {
    LLVMBuildUnreachable(c->builder);
    r_value = GEN_NOVALUE;
  }

  // If the right side returns, we don't branch to the post block.
  if(r_value != GEN_NOVALUE)
  {
    if(needed)
      r_value = gen_assign_cast(c, phi_type->use_type, r_value, right_type);

    if(r_value == NULL)
      return NULL;

    else_block = LLVMGetInsertBlock(c->builder);
    LLVMBuildBr(c->builder, post_block);
  }

  // If both sides return, we return a sentinal value.
  if(is_control_type(type))
    return GEN_NOVALUE;

  // Continue in the post block.
  LLVMPositionBuilderAtEnd(c->builder, post_block);

  if(needed)
  {
    LLVMValueRef phi = LLVMBuildPhi(c->builder, phi_type->use_type, "");

    if(l_value != GEN_NOVALUE)
      LLVMAddIncoming(phi, &l_value, &then_block, 1);

    if(r_value != GEN_NOVALUE)
      LLVMAddIncoming(phi, &r_value, &else_block, 1);

    return phi;
  }

  return GEN_NOTNEEDED;
}
Beispiel #16
0
static bool special_case_call(compile_t* c, ast_t* ast, LLVMValueRef* value)
{
  AST_GET_CHILDREN(ast, postfix, positional, named, question);

  if((ast_id(postfix) != TK_FUNREF) || (ast_id(named) != TK_NONE))
    return false;

  AST_GET_CHILDREN(postfix, receiver, method);
  ast_t* receiver_type = deferred_reify(c->frame->reify, ast_type(receiver),
    c->opt);

  const char* name = NULL;

  if(ast_id(receiver_type) == TK_NOMINAL)
  {
    AST_GET_CHILDREN(receiver_type, package, id);

    if(ast_name(package) == c->str_builtin)
      name = ast_name(id);
  }

  ast_free_unattached(receiver_type);

  if(name == NULL)
    return false;

  if(name == c->str_Bool)
    return special_case_operator(c, ast, value, true, true);

  if((name == c->str_I8) ||
    (name == c->str_I16) ||
    (name == c->str_I32) ||
    (name == c->str_I64) ||
    (name == c->str_ILong) ||
    (name == c->str_ISize) ||
    (name == c->str_U8) ||
    (name == c->str_U16) ||
    (name == c->str_U32) ||
    (name == c->str_U64) ||
    (name == c->str_ULong) ||
    (name == c->str_USize) ||
    (name == c->str_F32) ||
    (name == c->str_F64)
    )
  {
    return special_case_operator(c, ast, value, false, true);
  }

  if((name == c->str_I128) || (name == c->str_U128))
  {
    bool native128 = target_is_native128(c->opt->triple);
    return special_case_operator(c, ast, value, false, native128);
  }

  if(name == c->str_Platform)
  {
    *value = special_case_platform(c, ast);
    return true;
  }

  return false;
}
Beispiel #17
0
LLVMValueRef gen_try(compile_t* c, ast_t* ast)
{
  bool needed = is_result_needed(ast);
  AST_GET_CHILDREN(ast, body, else_clause, then_clause);

  ast_t* type = ast_type(ast);
  ast_t* body_type = ast_type(body);
  ast_t* else_type = ast_type(else_clause);

  reach_type_t* phi_type = NULL;

  // We will have no type if both branches have return statements.
  if(!is_control_type(type))
    phi_type = reach_type(c->reach, type);

  LLVMBasicBlockRef block = LLVMGetInsertBlock(c->builder);
  LLVMBasicBlockRef else_block = codegen_block(c, "try_else");
  LLVMBasicBlockRef post_block = NULL;

  if(!is_control_type(type))
    post_block = codegen_block(c, "try_post");

  // Keep a reference to the else block.
  codegen_pushtry(c, else_block);

  // Body block.
  LLVMPositionBuilderAtEnd(c->builder, block);
  LLVMValueRef body_value = gen_expr(c, body);

  if(body_value != GEN_NOVALUE)
  {
    if(needed)
    {
      body_value = gen_assign_cast(c, phi_type->use_type, body_value,
        body_type);
    }

    if(body_value == NULL)
      return NULL;

    gen_expr(c, then_clause);
    block = LLVMGetInsertBlock(c->builder);
    LLVMBuildBr(c->builder, post_block);
  }

  // Pop the try before generating the else block.
  codegen_poptry(c);

  // Else block.
  LLVMPositionBuilderAtEnd(c->builder, else_block);

  // The landing pad is marked as a cleanup, since exceptions are typeless and
  // valueless. The first landing pad is always the destination.
  LLVMTypeRef lp_elements[2];
  lp_elements[0] = c->void_ptr;
  lp_elements[1] = c->i32;
  LLVMTypeRef lp_type = LLVMStructTypeInContext(c->context, lp_elements, 2,
    false);

#if PONY_LLVM == 307 && LLVM_VERSION_PATCH == 0
  // This backwards-incompatible API change to LLVMBuildLandingPad is only in
  // LLVM 3.7.0. In 3.7.1 and all later versions, backward-compatibility was
  // restored.
  assert((c->frame->fun != NULL) && "No function in current frame!");
  LLVMSetPersonalityFn(c->frame->fun, c->personality);
  LLVMValueRef landing = LLVMBuildLandingPad(c->builder, lp_type, 1, "");
#else
  LLVMValueRef landing = LLVMBuildLandingPad(c->builder, lp_type,
    c->personality, 1, "");
#endif

  LLVMAddClause(landing, LLVMConstNull(c->void_ptr));

  LLVMValueRef else_value = gen_expr(c, else_clause);

  if(else_value != GEN_NOVALUE)
  {
    if(needed)
    {
      else_value = gen_assign_cast(c, phi_type->use_type, else_value,
        else_type);
    }

    if(else_value == NULL)
      return NULL;

    gen_expr(c, then_clause);

    else_block = LLVMGetInsertBlock(c->builder);
    LLVMBuildBr(c->builder, post_block);
  }

  // If both sides return, we return a sentinal value.
  if(is_control_type(type))
    return GEN_NOVALUE;

  // Continue in the post block.
  LLVMPositionBuilderAtEnd(c->builder, post_block);

  if(needed)
  {
    LLVMValueRef phi = LLVMBuildPhi(c->builder, phi_type->use_type, "");

    if(body_value != GEN_NOVALUE)
      LLVMAddIncoming(phi, &body_value, &block, 1);

    if(else_value != GEN_NOVALUE)
      LLVMAddIncoming(phi, &else_value, &else_block, 1);

    return phi;
  }

  return GEN_NOTNEEDED;
}
Beispiel #18
0
LLVMValueRef gen_funptr(compile_t* c, ast_t* ast)
{
  pony_assert((ast_id(ast) == TK_FUNREF) || (ast_id(ast) == TK_BEREF));
  AST_GET_CHILDREN(ast, receiver, method);
  ast_t* typeargs = NULL;

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

    default: {}
  }

  // Generate the receiver.
  LLVMValueRef value = gen_expr(c, receiver);

  // Get the receiver type.
  ast_t* type = deferred_reify(c->frame->reify, ast_type(receiver), c->opt);
  reach_type_t* t = reach_type(c->reach, type);
  pony_assert(t != NULL);

  const char* name = ast_name(method);
  token_id cap = cap_dispatch(type);
  reach_method_t* m = reach_method(t, cap, name, typeargs);
  LLVMValueRef funptr = dispatch_function(c, t, m, value);

  ast_free_unattached(type);

  if((m->cap != TK_AT) && (c->linkage != LLVMExternalLinkage))
  {
    // We must reset the function linkage and calling convention since we're
    // passing a function pointer to a FFI call. Bare methods always use the
    // external linkage and the C calling convention so we don't need to process
    // them.
    switch(t->underlying)
    {
      case TK_PRIMITIVE:
      case TK_STRUCT:
      case TK_CLASS:
      case TK_ACTOR:
      {
        compile_method_t* c_m = (compile_method_t*)m->c_method;
        LLVMSetFunctionCallConv(c_m->func, LLVMCCallConv);
        LLVMSetLinkage(c_m->func, LLVMExternalLinkage);
        break;
      }
      case TK_UNIONTYPE:
      case TK_ISECTTYPE:
      case TK_INTERFACE:
      case TK_TRAIT:
        set_method_external_interface(t, name, m->vtable_index);
        break;
      default:
        pony_assert(0);
        break;
    }
  }

  return funptr;
}
Beispiel #19
0
bool expr_match(pass_opt_t* opt, ast_t* ast)
{
  assert(ast_id(ast) == TK_MATCH);
  AST_GET_CHILDREN(ast, expr, cases, else_clause);

  // A literal match expression should have been caught by the cases, but check
  // again to avoid an assert if we've missed a case
  ast_t* expr_type = ast_type(expr);

  if(is_typecheck_error(expr_type))
    return false;

  if(is_type_literal(expr_type))
  {
    ast_error(expr, "cannot infer type for literal match expression");
    return false;
  }

  ast_t* cases_type = ast_type(cases);
  ast_t* else_type = ast_type(else_clause);

  if(is_typecheck_error(cases_type) || is_typecheck_error(else_type))
    return false;

  ast_t* type = NULL;
  size_t branch_count = 0;

  if(!is_control_type(cases_type))
  {
    type = control_type_add_branch(type, cases);
    ast_inheritbranch(ast, cases);
    branch_count++;
  }

  if(!is_control_type(else_type))
  {
    type = control_type_add_branch(type, else_clause);
    ast_inheritbranch(ast, else_clause);
    branch_count++;
  }

  if(type == NULL)
  {
    if(ast_sibling(ast) != NULL)
    {
      ast_error(ast_sibling(ast), "unreachable code");
      return false;
    }

    type = ast_from(ast, TK_MATCH);
  }

  ast_settype(ast, type);
  ast_inheritflags(ast);
  ast_consolidate_branches(ast, branch_count);
  literal_unify_control(ast, opt);

  // Push our symbol status to our parent scope.
  ast_inheritstatus(ast_parent(ast), ast);
  return true;
}
Beispiel #20
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, postfix, positional, named, question);
  AST_GET_CHILDREN(postfix, receiver, method);
  ast_t* typeargs = NULL;

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

  // 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 = deferred_reify(reify, method, c->opt);
      AST_GET_CHILDREN_NO_DECL(receiver, receiver, method);
      break;

    default: {}
  }

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

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

  ast_free_unattached(type);
  ast_free_unattached(typeargs);

  // Generate the arguments.
  size_t count = m->param_count + 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:
        args[0] = gen_constructor_receiver(c, t, ast);
        is_new_call = true;
        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(((compile_type_t*)t->c_type)->use_type);
  }

  // Static or virtual dispatch.
  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: {}
    }
  }

  bool bare = m->cap == TK_AT;
  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.
    codegen_debugloc(c, ast);
    gen_send_message(c, m, 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;
    }
  } else {
    LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(func));
    LLVMTypeRef* params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
    LLVMGetParamTypes(f_type, params + (bare ? 1 : 0));

    arg = ast_child(positional);
    i = 1;

    while(arg != NULL)
    {
      ast_t* arg_type = deferred_reify(reify, ast_type(arg), c->opt);
      args[i] = gen_assign_cast(c, params[i], args[i], arg_type);
      ast_free_unattached(arg_type);
      arg = ast_sibling(arg);
      i++;
    }

    uintptr_t arg_offset = 0;
    if(bare)
    {
      arg_offset = 1;
      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 + arg_offset, i, "", !bare);
      else
        r = codegen_call(c, func, args + arg_offset, i, !bare);

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

      codegen_debugloc(c, NULL);
      ponyint_pool_free_size(buf_size, params);
    }
  }

  // Bare methods with None return type return void, special case a None return
  // value.
  if(bare && is_none(m->result->ast))
    r = c->none_instance;

  // 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);
  return r;
}
Beispiel #21
0
static bool 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 false;

    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");
      errorframe_append(&frame, &info);
      errorframe_report(&frame, opt->check.errors);
      return false;
    }

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

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

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

  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 false;
    }
  }

  // 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 false;
  }

  // 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);
  return true;
}
Beispiel #22
0
LLVMValueRef gen_pattern_eq(compile_t* c, ast_t* pattern, LLVMValueRef r_value)
{
  // This is used for structural equality in pattern matching.
  ast_t* pattern_type = deferred_reify(c->frame->reify, ast_type(pattern),
    c->opt);

  if(ast_id(pattern_type) == TK_NOMINAL)
  {
    AST_GET_CHILDREN(pattern_type, package, id);

    // Special case equality on primitive types.
    if(ast_name(package) == c->str_builtin)
    {
      const char* name = ast_name(id);

      if((name == c->str_Bool) ||
        (name == c->str_I8) ||
        (name == c->str_I16) ||
        (name == c->str_I32) ||
        (name == c->str_I64) ||
        (name == c->str_I128) ||
        (name == c->str_ILong) ||
        (name == c->str_ISize) ||
        (name == c->str_U8) ||
        (name == c->str_U16) ||
        (name == c->str_U32) ||
        (name == c->str_U64) ||
        (name == c->str_U128) ||
        (name == c->str_ULong) ||
        (name == c->str_USize) ||
        (name == c->str_F32) ||
        (name == c->str_F64)
        )
      {
        ast_free_unattached(pattern_type);
        return gen_eq_rvalue(c, pattern, r_value, true);
      }
    }
  }

  // Generate the receiver.
  LLVMValueRef l_value = gen_expr(c, pattern);
  reach_type_t* t = reach_type(c->reach, pattern_type);
  pony_assert(t != NULL);

  // Static or virtual dispatch.
  token_id cap = cap_dispatch(pattern_type);
  reach_method_t* m = reach_method(t, cap, c->str_eq, NULL);
  LLVMValueRef func = dispatch_function(c, t, m, l_value);

  ast_free_unattached(pattern_type);

  if(func == NULL)
    return NULL;

  // Call the function. We know it isn't partial.
  LLVMValueRef args[2];
  args[0] = l_value;
  args[1] = r_value;

  codegen_debugloc(c, pattern);
  LLVMValueRef result = codegen_call(c, func, args, 2, true);
  codegen_debugloc(c, NULL);

  return result;
}
Beispiel #23
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;
    }
  }

  if(ok)
  {
    // 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 #24
0
static void print_type(printbuf_t* buffer, ast_t* type)
{
  switch(ast_id(type))
  {
    case TK_NOMINAL:
    {
      AST_GET_CHILDREN(type, package, id, typeargs, cap, ephemeral);
      ast_t* origpkg = ast_sibling(ephemeral);

      if(origpkg != NULL && ast_id(origpkg) != TK_NONE)
        printbuf(buffer, "%s.", ast_name(origpkg));

      ast_t* def = (ast_t*)ast_data(type);
      if(def != NULL)
        id = ast_child(def);

      printbuf(buffer, "%s", ast_nice_name(id));

      if(ast_id(typeargs) != TK_NONE)
        print_typeexpr(buffer, typeargs, ", ", true);

      if(ast_id(cap) != TK_NONE)
        printbuf(buffer, " %s", token_print(cap->t));

      if(ast_id(ephemeral) != TK_NONE)
        printbuf(buffer, "%s", token_print(ephemeral->t));

      break;
    }

    case TK_UNIONTYPE:
      print_typeexpr(buffer, type, " | ", false);
      break;

    case TK_ISECTTYPE:
      print_typeexpr(buffer, type, " & ", false);
      break;

    case TK_TUPLETYPE:
      print_typeexpr(buffer, type, ", ", false);
      break;

    case TK_TYPEPARAMREF:
    {
      AST_GET_CHILDREN(type, id, cap, ephemeral);
      printbuf(buffer, "%s", ast_nice_name(id));

      if(ast_id(cap) != TK_NONE)
        printbuf(buffer, " %s", token_print(cap->t));

      if(ast_id(ephemeral) != TK_NONE)
        printbuf(buffer, " %s", token_print(ephemeral->t));

      break;
    }

    case TK_ARROW:
    {
      AST_GET_CHILDREN(type, left, right);
      print_type(buffer, left);
      printbuf(buffer, "->");
      print_type(buffer, right);
      break;
    }

    case TK_THISTYPE:
      printbuf(buffer, "this");
      break;

    case TK_DONTCARE:
      printbuf(buffer, "_");
      break;

    case TK_FUNTYPE:
      printbuf(buffer, "function");
      break;

    case TK_INFERTYPE:
      printbuf(buffer, "to_infer");
      break;

    case TK_ERRORTYPE:
      printbuf(buffer, "<type error>");
      break;

    case TK_NONE:
      break;

    default:
      printbuf(buffer, "%s", token_print(type->t));
  }
}
Beispiel #25
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* opt, bool report_errors)
{
  pony_assert(astp != NULL);
  ast_t* literal_expr = *astp;
  pony_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, opt,
      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, opt,
        report_errors))
        return false;

      break;
    }

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

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

    case TK_ARRAY:
      if(!coerce_group(astp, target_type, chain, CHAIN_CARD_ARRAY, opt,
        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, opt,
        report_errors))
        return false;

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

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

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

      if(arg != NULL &&
        !coerce_literal_to_type(&arg, target_type, chain, opt,
        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, opt,
        report_errors))
        return false;

      break;
    }

    case TK_RECOVER:
    {
      ast_t* expr = ast_childidx(literal_expr, 1);
      if(!coerce_literal_to_type(&expr, target_type, chain, opt,
        report_errors))
        return false;

      break;
    }

    default:
      ast_error(opt->check.errors, literal_expr, "Internal error, coerce_literal_to_type node %s",
        ast_get_print(literal_expr));
      pony_assert(0);
      return false;
  }


  // Need to reprocess node now all the literals have types
  ast_settype(literal_expr, NULL);
  return (pass_expr(astp, opt) == AST_OK);
}
Beispiel #26
0
LLVMValueRef gen_while(compile_t* c, ast_t* ast)
{
  bool needed = is_result_needed(ast);
  AST_GET_CHILDREN(ast, cond, body, else_clause);

  ast_t* type = ast_type(ast);
  ast_t* body_type = ast_type(body);
  ast_t* else_type = ast_type(else_clause);

  reach_type_t* phi_type = NULL;

  if(needed && !is_control_type(type))
    phi_type = reach_type(c->reach, type);

  LLVMBasicBlockRef init_block = codegen_block(c, "while_init");
  LLVMBasicBlockRef body_block = codegen_block(c, "while_body");
  LLVMBasicBlockRef else_block = codegen_block(c, "while_else");
  LLVMBasicBlockRef post_block = NULL;
  LLVMBuildBr(c->builder, init_block);

  // start the post block so that a break can modify the phi node
  LLVMValueRef phi = GEN_NOTNEEDED;

  if(!is_control_type(type))
  {
    // Start the post block so that a break can modify the phi node.
    post_block = codegen_block(c, "while_post");
    LLVMPositionBuilderAtEnd(c->builder, post_block);

    if(needed)
      phi = LLVMBuildPhi(c->builder, phi_type->use_type, "");
  }

  // Push the loop status.
  codegen_pushloop(c, init_block, post_block, else_block);

  // init
  // This jumps either to the body or the else clause. This is not evaluated
  // on each loop iteration: only on the first entry or after a continue.
  LLVMPositionBuilderAtEnd(c->builder, init_block);
  LLVMValueRef i_value = gen_expr(c, cond);

  if(i_value == NULL)
    return NULL;

  LLVMValueRef test = LLVMBuildTrunc(c->builder, i_value, c->i1, "");
  LLVMBuildCondBr(c->builder, test, body_block, else_block);

  // Body.
  LLVMPositionBuilderAtEnd(c->builder, body_block);
  LLVMValueRef l_value = gen_expr(c, body);

  if(needed)
    l_value = gen_assign_cast(c, phi_type->use_type, l_value, body_type);

  if(l_value == NULL)
    return NULL;

  LLVMBasicBlockRef body_from = NULL;

  // If the body can't result in a value, don't generate the conditional
  // evaluation. This basic block for the body already has a terminator.
  if(l_value != GEN_NOVALUE)
  {
    // The body evaluates the condition itself, jumping either back to the body
    // or directly to the post block.
    LLVMValueRef c_value = gen_expr(c, cond);

    if(c_value == NULL)
      return NULL;

    body_from = LLVMGetInsertBlock(c->builder);
    LLVMValueRef test = LLVMBuildTrunc(c->builder, c_value, c->i1, "");
    LLVMBuildCondBr(c->builder, test, body_block, post_block);
  }

  // Don't need loop status for the else block.
  codegen_poploop(c);

  // else
  // If the loop doesn't generate a value (doesn't execute, or continues on the
  // last iteration), the else clause generates the value.
  LLVMPositionBuilderAtEnd(c->builder, else_block);
  LLVMValueRef r_value = gen_expr(c, else_clause);
  LLVMBasicBlockRef else_from = NULL;

  if(r_value != GEN_NOVALUE)
  {
    if(r_value == NULL)
      return NULL;

    if(needed)
      r_value = gen_assign_cast(c, phi_type->use_type, r_value, else_type);

    else_from = LLVMGetInsertBlock(c->builder);
    LLVMBuildBr(c->builder, post_block);
  }

  if(is_control_type(type))
    return GEN_NOVALUE;

  // post
  LLVMPositionBuilderAtEnd(c->builder, post_block);

  if(needed)
  {
    if(l_value != GEN_NOVALUE)
      LLVMAddIncoming(phi, &l_value, &body_from, 1);

    if(r_value != GEN_NOVALUE)
      LLVMAddIncoming(phi, &r_value, &else_from, 1);

    return phi;
  }

  return GEN_NOTNEEDED;
}
Beispiel #27
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:
      typeargs = method;
      AST_GET_CHILDREN_NO_DECL(receiver, receiver, method);
      break;

    default: {}
  }

  // Generate the receiver type.
  const char* method_name = ast_name(method);
  ast_t* type = ast_type(receiver);
  gentype_t g;

  if(!gentype(c, type, &g))
    return NULL;

  // Generate the arguments.
  LLVMTypeRef f_type = genfun_sig(c, &g, method_name, typeargs);

  if(f_type == NULL)
  {
    ast_error(ast, "couldn't create a signature for '%s'", method_name);
    return NULL;
  }

  size_t count = ast_childcount(positional) + 1;
  size_t buf_size = count * sizeof(void*);

  LLVMValueRef* args = (LLVMValueRef*)ponyint_pool_alloc_size(buf_size);
  LLVMTypeRef* params = (LLVMTypeRef*)ponyint_pool_alloc_size(buf_size);
  LLVMGetParamTypes(f_type, params);

  ast_t* arg = ast_child(positional);
  int i = 1;

  while(arg != NULL)
  {
    LLVMValueRef value = make_arg(c, params[i], arg);

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

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

  // 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, &g))
  {
    switch(ast_id(postfix))
    {
      case TK_NEWREF:
      case TK_NEWBEREF:
      {
        ast_t* parent = ast_parent(ast);
        ast_t* sibling = ast_sibling(ast);

        // If we're constructing an embed field, pass a pointer to the field
        // as the receiver. Otherwise, allocate an object.
        if((ast_id(parent) == TK_ASSIGN) && (ast_id(sibling) == TK_EMBEDREF))
          args[0] = gen_fieldptr(c, sibling);
        else
          args[0] = gencall_alloc(c, &g);
        break;
      }

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

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

  // Always emit location info for a call, to prevent inlining errors. This may
  // be disabled in dispatch_function, if the target function has no debug
  // info set.
  ast_setdebug(ast, true);
  dwarf_location(&c->dwarf, ast);

  // Static or virtual dispatch.
  LLVMValueRef func = dispatch_function(c, ast, &g, args[0], method_name,
    typeargs);

  LLVMValueRef r = NULL;

  if(func != NULL)
  {
    // If we can error out and we have an invoke target, generate an invoke
    // instead of a call.
    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);
  }

  ponyint_pool_free_size(buf_size, args);
  ponyint_pool_free_size(buf_size, params);
  return r;
}
Beispiel #28
0
LLVMValueRef gen_repeat(compile_t* c, ast_t* ast)
{
  bool needed = is_result_needed(ast);
  AST_GET_CHILDREN(ast, body, cond, else_clause);

  ast_t* type = ast_type(ast);
  ast_t* body_type = ast_type(body);
  ast_t* else_type = ast_type(else_clause);

  reach_type_t* phi_type = NULL;

  if(needed && !is_control_type(type))
    phi_type = reach_type(c->reach, type);

  LLVMBasicBlockRef body_block = codegen_block(c, "repeat_body");
  LLVMBasicBlockRef cond_block = codegen_block(c, "repeat_cond");
  LLVMBasicBlockRef else_block = codegen_block(c, "repeat_else");
  LLVMBasicBlockRef post_block = NULL;
  LLVMBuildBr(c->builder, body_block);

  // start the post block so that a break can modify the phi node
  LLVMValueRef phi = GEN_NOTNEEDED;

  if(!is_control_type(type))
  {
    // Start the post block so that a break can modify the phi node.
    post_block = codegen_block(c, "repeat_post");
    LLVMPositionBuilderAtEnd(c->builder, post_block);

    if(needed)
      phi = LLVMBuildPhi(c->builder, phi_type->use_type, "");
  }

  // Push the loop status.
  codegen_pushloop(c, cond_block, post_block, else_block);

  // Body.
  LLVMPositionBuilderAtEnd(c->builder, body_block);
  LLVMValueRef value = gen_expr(c, body);

  if(needed)
    value = gen_assign_cast(c, phi_type->use_type, value, body_type);

  if(value == NULL)
    return NULL;

  LLVMBasicBlockRef body_from = NULL;

  // If the body can't result in a value, don't generate the conditional
  // evaluation. This basic block for the body already has a terminator.
  if(value != GEN_NOVALUE)
  {
    // The body evaluates the condition itself, jumping either back to the body
    // or directly to the post block.
    LLVMValueRef c_value = gen_expr(c, cond);

    if(c_value == NULL)
      return NULL;

    body_from = LLVMGetInsertBlock(c->builder);
    LLVMValueRef test = LLVMBuildTrunc(c->builder, c_value, c->i1, "");
    LLVMBuildCondBr(c->builder, test, post_block, body_block);
  }

  // cond block
  // This is only evaluated from a continue, jumping either back to the body
  // or to the else block.
  LLVMPositionBuilderAtEnd(c->builder, cond_block);
  LLVMValueRef i_value = gen_expr(c, cond);

  LLVMValueRef test = LLVMBuildTrunc(c->builder, i_value, c->i1, "");
  LLVMBuildCondBr(c->builder, test, else_block, body_block);

  // Don't need loop status for the else block.
  codegen_poploop(c);

  // else
  // Only happens for a continue in the last iteration.
  LLVMPositionBuilderAtEnd(c->builder, else_block);
  LLVMValueRef else_value = gen_expr(c, else_clause);
  LLVMBasicBlockRef else_from = NULL;

  if(else_value == NULL)
    return NULL;

  if(needed)
    else_value = gen_assign_cast(c, phi_type->use_type, else_value, else_type);

  if(else_value != GEN_NOVALUE)
  {
    else_from = LLVMGetInsertBlock(c->builder);
    LLVMBuildBr(c->builder, post_block);
  }

  if(is_control_type(type))
    return GEN_NOVALUE;

  // post
  LLVMPositionBuilderAtEnd(c->builder, post_block);

  if(needed)
  {
    if(value != GEN_NOVALUE)
      LLVMAddIncoming(phi, &value, &body_from, 1);

    if(else_value != GEN_NOVALUE)
      LLVMAddIncoming(phi, &else_value, &else_from, 1);

    return phi;
  }

  return GEN_NOTNEEDED;
}
Beispiel #29
0
// Write the given type to the current type file
static void doc_type(docgen_t* docgen, ast_t* type)
{
  assert(docgen != NULL);
  assert(docgen->type_file != NULL);
  assert(type != NULL);

  switch(ast_id(type))
  {
    case TK_NOMINAL:
    {
      AST_GET_CHILDREN(type, package, id, tparams, cap, ephemeral);

      // Find type we reference so we can link to it
      ast_t* target = (ast_t*)ast_data(type);
      assert(target != NULL);

      size_t link_len;
      char* tqfn = write_tqfn(target, NULL, &link_len);

      // Links are of the form: [text](target)
      fprintf(docgen->type_file, "[%s](%s)", ast_name(id), tqfn);
      pool_free_size(link_len, tqfn);

      doc_type_list(docgen, tparams, "\\[", ", ", "\\]");

      const char* cap_text = doc_get_cap(cap);
      if(cap_text != NULL)
        fprintf(docgen->type_file, " %s", cap_text);

      if(ast_id(ephemeral) != TK_NONE)
        fprintf(docgen->type_file, "%s", ast_get_print(ephemeral));

      break;
    }

    case TK_UNIONTYPE:
      doc_type_list(docgen, type, "(", " | ", ")");
      break;

    case TK_ISECTTYPE:
      doc_type_list(docgen, type, "(", " & ", ")");
      break;

    case TK_TUPLETYPE:
      doc_type_list(docgen, type, "(", " , ", ")");
      break;

    case TK_TYPEPARAMREF:
    {
      AST_GET_CHILDREN(type, id, cap, ephemeral);
      fprintf(docgen->type_file, "%s", ast_name(id));

      const char* cap_text = doc_get_cap(cap);
      if(cap_text != NULL)
        fprintf(docgen->type_file, " %s", cap_text);

      if(ast_id(ephemeral) != TK_NONE)
        fprintf(docgen->type_file, "%s", ast_get_print(ephemeral));

      break;
    }

    case TK_ARROW:
    {
      AST_GET_CHILDREN(type, left, right);
      doc_type(docgen, left);
      fprintf(docgen->type_file, "->");
      doc_type(docgen, right);
      break;
    }

    case TK_THISTYPE:
      fprintf(docgen->type_file, "this");
      break;

    case TK_BOXTYPE:
      fprintf(docgen->type_file, "box");
      break;

    default:
      assert(0);
  }
}
Beispiel #30
0
ast_t* viewpoint_reifytypeparam(ast_t* type, ast_t* typeparamref)
{
  pony_assert(ast_id(typeparamref) == TK_TYPEPARAMREF);
  AST_GET_CHILDREN(typeparamref, id, cap, eph);

  switch(ast_id(cap))
  {
    case TK_ISO:
    case TK_TRN:
    case TK_REF:
    case TK_VAL:
    case TK_BOX:
    case TK_TAG:
      return NULL;

    case TK_CAP_SEND:
    {
      ast_t* tuple = ast_from(type, TK_TUPLETYPE);
      replace_typeparam(tuple, type, typeparamref, TK_ISO, ast_id(eph));
      replace_typeparam(tuple, type, typeparamref, TK_VAL, TK_NONE);
      replace_typeparam(tuple, type, typeparamref, TK_TAG, TK_NONE);
      return tuple;
    }

    case TK_CAP_SHARE:
    {
      ast_t* tuple = ast_from(type, TK_TUPLETYPE);
      replace_typeparam(tuple, type, typeparamref, TK_VAL, TK_NONE);
      replace_typeparam(tuple, type, typeparamref, TK_TAG, TK_NONE);
      return tuple;
    }

    case TK_CAP_READ:
    {
      ast_t* tuple = ast_from(type, TK_TUPLETYPE);
      replace_typeparam(tuple, type, typeparamref, TK_REF, TK_NONE);
      replace_typeparam(tuple, type, typeparamref, TK_VAL, TK_NONE);
      replace_typeparam(tuple, type, typeparamref, TK_BOX, TK_NONE);
      return tuple;
    }

    case TK_CAP_ALIAS:
    {
      ast_t* tuple = ast_from(type, TK_TUPLETYPE);
      replace_typeparam(tuple, type, typeparamref, TK_REF, TK_NONE);
      replace_typeparam(tuple, type, typeparamref, TK_VAL, TK_NONE);
      replace_typeparam(tuple, type, typeparamref, TK_BOX, TK_NONE);
      replace_typeparam(tuple, type, typeparamref, TK_TAG, TK_NONE);
      return tuple;
    }

    case TK_CAP_ANY:
    {
      ast_t* tuple = ast_from(type, TK_TUPLETYPE);
      replace_typeparam(tuple, type, typeparamref, TK_ISO, ast_id(eph));
      replace_typeparam(tuple, type, typeparamref, TK_TRN, ast_id(eph));
      replace_typeparam(tuple, type, typeparamref, TK_REF, TK_NONE);
      replace_typeparam(tuple, type, typeparamref, TK_VAL, TK_NONE);
      replace_typeparam(tuple, type, typeparamref, TK_BOX, TK_NONE);
      replace_typeparam(tuple, type, typeparamref, TK_TAG, TK_NONE);
      return tuple;
    }

    default: {}
  }

  pony_assert(0);
  return NULL;
}