Example #1
0
bool literal_is(ast_t* ast, pass_opt_t* opt)
{
  pony_assert(ast != NULL);
  pony_assert(ast_id(ast) == TK_IS || ast_id(ast) == TK_ISNT);

  AST_GET_CHILDREN(ast, left, right);

  ast_t* l_type = ast_type(left);
  ast_t* r_type = ast_type(right);

  if(is_typecheck_error(l_type) || is_typecheck_error(r_type))
    return false;

  if(!is_type_literal(l_type) && !is_type_literal(r_type))
    // No literals here.
    return true;

  if(is_type_literal(l_type) && !is_type_literal(r_type))
  {
    // Coerce left to type of right.
    return coerce_literals(&left, r_type, opt);
  }

  if(!is_type_literal(l_type) && is_type_literal(r_type))
  {
    // Coerce right to type of left.
    return coerce_literals(&right, l_type, opt);
  }

  // Both sides are literals, that's a problem.
  pony_assert(is_type_literal(l_type));
  pony_assert(is_type_literal(r_type));
  ast_error(opt->check.errors, ast, "Cannot infer type of operands");
  return false;
}
Example #2
0
bool expr_repeat(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, body, cond, else_clause);

  ast_t* body_type = ast_type(body);
  ast_t* cond_type = ast_type(cond);
  ast_t* else_type = ast_type(else_clause);

  if(is_typecheck_error(cond_type))
    return false;

  if(!is_bool(cond_type))
  {
    ast_error(opt->check.errors, cond, "condition must be a Bool");
    return false;
  }

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

  // All consumes have to be in scope when the loop body finishes.
  errorframe_t errorf = NULL;
  if(!ast_all_consumes_in_scope(body, body, &errorf))
  {
    errorframe_report(&errorf, opt->check.errors);
    return false;
  }

  // Union with any existing type due to a break expression.
  ast_t* type = ast_type(ast);

  // No symbol status is inherited from the loop body or condition. Nothing
  // from outside can be consumed, and definitions inside may not occur.
  if(!is_control_type(body_type))
    type = control_type_add_branch(opt, type, body);

  if(!is_control_type(else_type))
  {
    type = control_type_add_branch(opt, type, else_clause);
    ast_inheritbranch(ast, else_clause);

    // Use a branch count of two instead of one. This means we will pick up any
    // consumes, but not any definitions, since definitions may not occur.
    ast_consolidate_branches(ast, 2);
  }

  if(type == NULL)
    type = ast_from(ast, TK_REPEAT);

  ast_settype(ast, type);
  literal_unify_control(ast, opt);

  // Push our symbol status to our parent scope.
  ast_inheritstatus(ast_parent(ast), ast);
  return true;
}
Example #3
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;

  ast_t* type = NULL;

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

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

  if(type == NULL)
  {
    if(ast_sibling(ast) != NULL)
    {
      ast_error(opt->check.errors, 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(opt->check.errors, then_clause,
      "then clause always terminates the function");
    return false;
  }

  if(is_type_literal(then_type))
  {
    ast_error(opt->check.errors, then_clause,
      "Cannot infer type of unused literal");
    return false;
  }

  ast_settype(ast, type);

  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;
}
Example #4
0
static bool tuple_access(ast_t* ast)
{
  // Left is a postfix expression, right is a lookup name.
  ast_t* left = ast_child(ast);
  ast_t* right = ast_sibling(left);
  ast_t* type = ast_type(left);

  if(is_typecheck_error(type))
    return false;

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

  // Make sure our index is in bounds.
  type = ast_childidx(type, (size_t)ast_int(right));

  if(type == NULL)
  {
    ast_error(right, "tuple index is out of bounds");
    return false;
  }

  ast_setid(ast, TK_FLETREF);
  ast_settype(ast, type);
  ast_inheritflags(ast);
  return true;
}
Example #5
0
bool expr_recover(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, cap, expr);
  ast_t* type = ast_type(expr);

  if(is_typecheck_error(type))
    return false;

  if(is_type_literal(type))
  {
    make_literal_type(ast);
    return true;
  }

  ast_t* r_type = recover_type(type, ast_id(cap));

  if(r_type == NULL)
  {
    ast_error(opt->check.errors, ast, "can't recover to this capability");
    ast_error_continue(opt->check.errors, expr, "expression type is %s",
      ast_print_type(type));
    return false;
  }

  ast_settype(ast, r_type);

  // Push our symbol status to our parent scope.
  ast_inheritstatus(ast_parent(ast), expr);
  return true;
}
Example #6
0
static bool expr_addressof_ffi(pass_opt_t* opt, ast_t* ast)
{
  ast_t* expr = ast_child(ast);

  switch(ast_id(expr))
  {
    case TK_FVARREF:
    case TK_VARREF:
    case TK_FLETREF:
    case TK_LETREF:
      break;

    case TK_PARAMREF:
      ast_error(ast, "can't take the address of a function parameter");
      return false;

    default:
      ast_error(ast, "can only take the address of a field or local variable");
      return false;
  }

  // Set the type to Pointer[ast_type(expr)].
  ast_t* expr_type = ast_type(expr);

  if(is_typecheck_error(expr_type))
    return false;

  ast_t* type = type_pointer_to(opt, expr_type);
  ast_settype(ast, type);
  return true;
}
Example #7
0
static bool check_type_params(ast_t** astp)
{
  ast_t* lhs = *astp;
  ast_t* type = ast_type(lhs);

  if(is_typecheck_error(type))
    return false;

  ast_t* typeparams = ast_childidx(type, 1);
  assert(ast_id(type) == TK_FUNTYPE);

  if(ast_id(typeparams) == TK_NONE)
    return true;

  BUILD(typeargs, typeparams, NODE(TK_TYPEARGS));

  if(!check_constraints(typeparams, typeargs, true))
  {
    ast_free_unattached(typeargs);
    return false;
  }

  type = reify(type, typeparams, typeargs);
  typeparams = ast_childidx(type, 1);
  ast_replace(&typeparams, ast_from(typeparams, TK_NONE));

  REPLACE(astp, NODE(ast_id(lhs), TREE(lhs) TREE(typeargs)));
  ast_settype(*astp, type);

  return true;
}
Example #8
0
static bool auto_recover_call(ast_t* ast, ast_t* receiver_type,
  ast_t* positional, ast_t* result)
{
  // We can recover the receiver (ie not alias the receiver type) if all
  // arguments are safe and the result is either safe or unused.
  if(is_result_needed(ast) && !safe_to_autorecover(receiver_type, result))
    return false;

  ast_t* arg = ast_child(positional);

  while(arg != NULL)
  {
    if(ast_id(arg) != TK_NONE)
    {
      ast_t* arg_type = ast_type(arg);

      if(is_typecheck_error(arg_type))
        return false;

      ast_t* a_type = alias(arg_type);
      bool ok = safe_to_autorecover(receiver_type, a_type);
      ast_free_unattached(a_type);

      if(!ok)
        return false;
    }

    arg = ast_sibling(arg);
  }

  return true;
}
Example #9
0
bool expr_param(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, id, type, init);
  ast_settype(ast, type);
  bool ok = true;

  if(ast_id(init) != TK_NONE)
  {
    // Initialiser type must match declared type.
    if(!coerce_literals(&init, type, opt))
      return false;

    ast_t* init_type = ast_type(init);

    if(is_typecheck_error(init_type))
      return false;

    init_type = alias(init_type);
    errorframe_t err = NULL;

    if(!is_subtype(init_type, type, &err, opt))
    {
      errorframe_t err2 = NULL;
      ast_error_frame(&err2, init,
        "default argument is not a subtype of the parameter type");
      errorframe_append(&err2, &err);
      errorframe_report(&err2, opt->check.errors);
      ok = false;
    }

    ast_free_unattached(init_type);
  }

  return ok;
}
Example #10
0
// Unify all the branches of the given AST to the same type
static bool unify(ast_t* ast, pass_opt_t* options, bool report_errors)
{
  assert(ast != NULL);
  ast_t* type = ast_type(ast);

  if(is_typecheck_error(type))
    return false;

  if(!is_type_literal(type)) // Not literal, nothing to unify
    return true;

  assert(type != NULL);
  ast_t* non_literal = ast_type(type);

  if(non_literal != NULL)
  {
    // Type has a non-literal element, coerce literals to that
    lit_chain_t chain;
    chain_init_head(&chain);
    return coerce_literal_to_type(&ast, non_literal, &chain, options,
      report_errors);
    //return coerce_literals(&ast, non_literal, options);
  }

  // Still a pure literal
  return true;
}
Example #11
0
bool expr_recover(ast_t* ast)
{
  AST_GET_CHILDREN(ast, cap, expr);
  ast_t* type = ast_type(expr);

  if(is_typecheck_error(type))
    return false;

  if(is_type_literal(type))
  {
    make_literal_type(ast);
    return true;
  }

  ast_t* r_type = recover_type(type, ast_id(cap));

  if(r_type == NULL)
  {
    errorframe_t frame = NULL;
    ast_error_frame(&frame, ast, "can't recover to this capability");
    ast_error_frame(&frame, expr, "expression type is %s",
      ast_print_type(type));
    errorframe_report(&frame);
    return false;
  }

  ast_settype(ast, r_type);
  ast_inheritflags(ast);

  // Push our symbol status to our parent scope.
  ast_inheritstatus(ast_parent(ast), expr);
  return true;
}
Example #12
0
bool expr_field(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, id, type, init);

  if(ast_id(init) != TK_NONE)
  {
    // Initialiser type must match declared type.
    if(!coerce_literals(&init, type, opt))
      return false;

    ast_t* init_type = ast_type(init);

    if(is_typecheck_error(init_type))
      return false;

    init_type = alias(init_type);

    if(!is_subtype(init_type, type))
    {
      ast_error(init,
        "field/param initialiser is not a subtype of the field/param type");
      ast_error(type, "field/param type: %s", ast_print_type(type));
      ast_error(init, "initialiser type: %s", ast_print_type(init_type));
      ast_free_unattached(init_type);
      return false;
    }

    ast_free_unattached(init_type);
  }

  ast_settype(ast, type);
  return true;
}
Example #13
0
static bool method_call(pass_opt_t* opt, ast_t* ast)
{
  if(!method_application(opt, ast, false))
    return false;

  AST_GET_CHILDREN(ast, positional, namedargs, lhs);
  ast_t* type = ast_type(lhs);

  if(is_typecheck_error(type))
    return false;

  AST_GET_CHILDREN(type, cap, typeparams, params, result);
  ast_settype(ast, result);
  ast_inheritflags(ast);

  switch(ast_id(lhs))
  {
    case TK_NEWBEREF:
    case TK_BEREF:
      ast_setsend(ast);
      return true;

    case TK_NEWREF:
    case TK_FUNREF:
      ast_setmightsend(ast);
      return true;

    default: {}
  }

  assert(0);
  return false;
}
Example #14
0
static bool member_access(pass_opt_t* opt, ast_t* ast, bool partial)
{
  // Left is a postfix expression, right is an id.
  AST_GET_CHILDREN(ast, left, right);
  assert(ast_id(right) == TK_ID);
  ast_t* type = ast_type(left);

  if(is_typecheck_error(type))
    return false;

  ast_t* find = lookup(opt, ast, type, ast_name(right));

  if(find == NULL)
    return false;

  bool ret = true;

  switch(ast_id(find))
  {
    case TK_TYPEPARAM:
      ast_error(opt->check.errors, right,
        "can't look up a typeparam on an expression");
      ret = false;
      break;

    case TK_FVAR:
      if(!expr_fieldref(opt, ast, find, TK_FVARREF))
        return false;
      break;

    case TK_FLET:
      if(!expr_fieldref(opt, ast, find, TK_FLETREF))
        return false;
      break;

    case TK_EMBED:
      if(!expr_fieldref(opt, ast, find, TK_EMBEDREF))
        return false;
      break;

    case TK_NEW:
    case TK_BE:
    case TK_FUN:
      ret = method_access(opt, ast, find);
      break;

    default:
      assert(0);
      ret = false;
      break;
  }

  ast_free_unattached(find);

  if(!partial)
    ast_inheritflags(ast);

  return ret;
}
Example #15
0
static bool method_application(pass_opt_t* opt, ast_t* ast, bool partial)
{
  AST_GET_CHILDREN(ast, positional, namedargs, question, lhs);

  if(!method_check_type_params(opt, &lhs))
    return false;

  ast_t* type = ast_type(lhs);

  if(is_typecheck_error(type))
    return false;

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

  if(!extend_positional_args(opt, params, positional))
    return false;

  if(!apply_named_args(opt, params, positional, namedargs))
    return false;

  if(!check_arg_types(opt, params, positional, partial))
    return false;

  switch(ast_id(lhs))
  {
    case TK_FUNREF:
    case TK_FUNAPP:
      if(ast_id(ast_child(type)) != TK_AT)
      {
        if(!check_receiver_cap(opt, ast, NULL))
          return false;

        if(!check_nonsendable_recover(opt, ast))
          return false;
      } else {
        ast_t* receiver = ast_child(lhs);

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

        ast_t* recv_type = ast_type(receiver);
        if(!is_known(recv_type) && (ast_id(receiver) == TK_TYPEREF))
        {
          ast_error(opt->check.errors, lhs, "a bare method cannot be called on "
            "an abstract type reference");
          return false;
        }
      }

      break;

    default: {}
  }

  return true;
}
Example #16
0
bool expr_consume(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, cap, term);
  ast_t* type = ast_type(term);

  if(is_typecheck_error(type))
    return false;

  const char* name = NULL;

  switch(ast_id(term))
  {
    case TK_VARREF:
    case TK_LETREF:
    case TK_PARAMREF:
    {
      ast_t* id = ast_child(term);
      name = ast_name(id);
      break;
    }

    case TK_THIS:
    {
      name = stringtab("this");
      break;
    }

    default:
      ast_error(opt->check.errors, ast,
        "consume must take 'this', a local, or a parameter");
      return false;
  }

  // Can't consume from an outer scope while in a loop condition.
  if((opt->check.frame->loop_cond != NULL) &&
    !ast_within_scope(opt->check.frame->loop_cond, ast, name))
  {
    ast_error(opt->check.errors, ast,
      "can't consume from an outer scope in a loop condition");
    return false;
  }

  ast_setstatus(ast, name, SYM_CONSUMED);

  token_id tcap = ast_id(cap);
  ast_t* c_type = consume_type(type, tcap);

  if(c_type == NULL)
  {
    ast_error(opt->check.errors, ast, "can't consume to this capability");
    ast_error_continue(opt->check.errors, term, "expression type is %s",
      ast_print_type(type));
    return false;
  }

  ast_settype(ast, c_type);
  return true;
}
Example #17
0
File: control.c Project: ozra/ponyc
bool expr_if(pass_opt_t* opt, ast_t* ast)
{
    ast_t* cond = ast_child(ast);
    ast_t* left = ast_sibling(cond);
    ast_t* right = ast_sibling(left);
    ast_t* cond_type = ast_type(cond);

    if(is_typecheck_error(cond_type))
        return false;

    if(!is_bool(cond_type))
    {
        ast_error(cond, "condition must be a Bool");
        return false;
    }

    ast_t* l_type = ast_type(left);
    ast_t* r_type = ast_type(right);

    ast_t* type = NULL;
    size_t branch_count = 0;

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

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

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

        type = ast_from(ast, TK_IF);
    }

    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;
}
Example #18
0
bool expr_literal(pass_opt_t* opt, ast_t* ast, const char* name)
{
  ast_t* type = type_builtin(opt, ast, name);

  if(is_typecheck_error(type))
    return false;

  ast_settype(ast, type);
  return true;
}
Example #19
0
bool expr_field(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, id, type, init);

  // An embedded field must have a known, non-actor type.
  if(ast_id(ast) == TK_EMBED)
  {
    if(!is_known(type) || is_actor(type))
    {
      ast_error(ast, "embedded fields must always be primitives or classes");
      return false;
    }
  }

  if(ast_id(init) != TK_NONE)
  {
    // Initialiser type must match declared type.
    if(!coerce_literals(&init, type, opt))
      return false;

    ast_t* init_type = ast_type(init);

    if(is_typecheck_error(init_type))
      return false;

    init_type = alias(init_type);

    if(!is_subtype(init_type, type))
    {
      ast_error(init,
        "field/param initialiser is not a subtype of the field/param type");
      ast_error(type, "field/param type: %s", ast_print_type(type));
      ast_error(init, "initialiser type: %s", ast_print_type(init_type));
      ast_free_unattached(init_type);
      return false;
    }

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

    ast_free_unattached(init_type);
  }

  ast_settype(ast, type);
  return true;
}
Example #20
0
ast_t* control_type_add_branch(ast_t* control_type, ast_t* branch)
{
  assert(branch != NULL);

  ast_t* branch_type = ast_type(branch);

  if(is_typecheck_error(branch_type))
    return branch_type;

  if(is_type_literal(branch_type))
  {
    // The new branch is a literal
    if(control_type == NULL)
      control_type = ast_from(branch, TK_LITERAL);

    if(ast_id(control_type) != TK_LITERAL)
    {
      // The current control type is not a literal, fix that
      ast_t* old_control = control_type;
      control_type = ast_from(branch, TK_LITERAL);
      ast_settype(control_type, old_control);
    }

    assert(ast_id(control_type) == TK_LITERAL);

    // Add a literal branch reference to the new branch
    ast_t* member = ast_from(branch, TK_LITERALBRANCH);
    ast_setdata(member, (void*)branch);
    ast_append(control_type, member);

    ast_t* branch_non_lit = ast_type(branch_type);

    if(branch_non_lit != NULL)
    {
      // The branch's literal type has a non-literal component
      ast_t* non_literal_type = ast_type(control_type);
      ast_settype(control_type, type_union(non_literal_type, branch_non_lit));
    }

    return control_type;
  }

  if(control_type != NULL && ast_id(control_type) == TK_LITERAL)
  {
    // New branch is not literal, but the control structure is
    // Add new branch type to the control structure's non-literal aspect
    ast_t* non_literal_type = ast_type(control_type);
    non_literal_type = type_union(non_literal_type, branch_type);
    ast_settype(control_type, non_literal_type);
    return control_type;
  }

  // No literals here, just union the types
  return type_union(control_type, branch_type);
}
Example #21
0
// Determine the UIF types that the given type may be
static int uifset(pass_opt_t* opt, ast_t* type, lit_chain_t* chain)
{
  assert(chain != NULL);

  if(is_typecheck_error(type))
    return UIF_NO_TYPES;

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

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

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

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

      return uifset_formal_param(opt, type, chain);

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

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

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

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

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

      return uifset_simple_type(opt, type);

    default:
      ast_error(type, "Internal error: uif type, node %d", ast_id(type));
      assert(0);
      return UIF_ERROR;
  }
}
Example #22
0
// Coerce a literal group (tuple or array) to be the specified target type
static bool coerce_group(ast_t** astp, ast_t* target_type, lit_chain_t* chain,
  size_t cardinality, pass_opt_t* options, bool report_errors)
{
  pony_assert(astp != NULL);
  ast_t* literal_expr = *astp;
  pony_assert(literal_expr != NULL);
  pony_assert(ast_id(literal_expr) == TK_TUPLE || ast_id(literal_expr) == TK_ARRAY);
  pony_assert(chain != NULL);
  pony_assert(cardinality != CHAIN_CARD_BASE);

  size_t i = 0;
  lit_chain_t link;

  chain_add(chain, &link, cardinality);

  if(ast_id(literal_expr) == TK_ARRAY)
  {
    // The first child of an array AST is the forced type, the second child is
    // the sequence of elements.
    literal_expr = ast_childidx(literal_expr, 1);
  }

  // Process each group element separately
  for(ast_t* p = ast_child(literal_expr); p != NULL; p = ast_sibling(p))
  {
    ast_t* p_type = ast_type(p);

    if(is_typecheck_error(p_type))
      return false;

    if(is_type_literal(p_type))
    {
      // This element is a literal
      if(cardinality != CHAIN_CARD_ARRAY)
      {
        chain_clear_cache(&link);
        link.index = i;
      }

      if(!coerce_literal_to_type(&p, target_type, &link, options,
        report_errors))
        return false;
    }

    i++;
  }

  chain_remove(chain);
  return true;
}
Example #23
0
bool expr_fieldref(pass_opt_t* opt, ast_t* ast, ast_t* find, token_id tid)
{
  AST_GET_CHILDREN(ast, left, right);
  ast_t* l_type = ast_type(left);

  if(is_typecheck_error(l_type))
    return false;

  AST_GET_CHILDREN(find, id, f_type, init);

  // Viewpoint adapted type of the field.
  ast_t* type = viewpoint_type(l_type, f_type);

  if(ast_id(type) == TK_ARROW)
  {
    ast_t* upper = viewpoint_upper(type);

    if(upper == NULL)
    {
      ast_error(ast, "can't read a field through %s", ast_print_type(l_type));
      return false;
    }

    ast_free_unattached(upper);
  }

  // Set the unadapted field type.
  ast_settype(right, f_type);

  // Set the type so that it isn't free'd as unattached.
  ast_setid(ast, tid);
  ast_settype(ast, type);

  if(ast_id(left) == TK_THIS)
  {
    // Handle symbol status if the left side is 'this'.
    ast_t* id = ast_child(find);
    const char* name = ast_name(id);

    sym_status_t status;
    ast_get(ast, name, &status);

    if(!valid_reference(opt, ast, type, status))
      return false;
  }

  return true;
}
Example #24
0
File: call.c Project: enigma/ponyc
static bool method_call(pass_opt_t* opt, ast_t* ast)
{
  if(!method_application(opt, ast, false))
    return false;

  AST_GET_CHILDREN(ast, positional, namedargs, lhs);
  ast_t* type = ast_type(lhs);

  if(is_typecheck_error(type))
    return false;

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

  return true;
}
Example #25
0
static bool auto_recover_call(ast_t* ast, ast_t* receiver_type,
  ast_t* positional, ast_t* result)
{
  switch(ast_id(ast))
  {
    case TK_FUNREF:
    case TK_FUNAPP:
    case TK_FUNCHAIN:
      break;

    default:
      pony_assert(0);
      break;
  }

  // We can recover the receiver (ie not alias the receiver type) if all
  // arguments are safe and the result is either safe or unused.
  // The result of a chained method is always unused.
  ast_t* call = ast_parent(ast);
  if(is_result_needed(call) && !safe_to_autorecover(receiver_type, result))
    return false;

  ast_t* arg = ast_child(positional);

  while(arg != NULL)
  {
    if(ast_id(arg) != TK_NONE)
    {
      ast_t* arg_type = ast_type(arg);

      if(is_typecheck_error(arg_type))
        return false;

      ast_t* a_type = alias(arg_type);
      bool ok = safe_to_autorecover(receiver_type, a_type);
      ast_free_unattached(a_type);

      if(!ok)
        return false;
    }

    arg = ast_sibling(arg);
  }

  return true;
}
Example #26
0
static bool tuple_access(pass_opt_t* opt, ast_t* ast)
{
  // Left is a postfix expression, right is a lookup name.
  ast_t* left = ast_child(ast);
  ast_t* right = ast_sibling(left);
  ast_t* type = ast_type(left);

  if(is_typecheck_error(type))
    return false;

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

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

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

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

  ast_setid(ast, TK_FLETREF);
  ast_settype(ast, type);
  ast_inheritflags(ast);
  return true;
}
Example #27
0
bool expr_field(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, id, type, init);

  if(ast_id(init) != TK_NONE)
  {
    // Only parameters have initialisers. Field initialisers are moved into
    // constructors in the sugar pass.
    assert(ast_id(ast) == TK_PARAM);

    // Initialiser type must match declared type.
    if(!coerce_literals(&init, type, opt))
      return false;

    ast_t* init_type = ast_type(init);

    if(is_typecheck_error(init_type))
      return false;

    init_type = alias(init_type);

    errorframe_t info = NULL;
    if(!is_subtype(init_type, type, &info))
    {
      errorframe_t frame = NULL;
      ast_error_frame(&frame, init,
        "default argument is not a subtype of the parameter type");
      ast_error_frame(&frame, type, "parameter type: %s",
        ast_print_type(type));
      ast_error_frame(&frame, init, "default argument type: %s",
        ast_print_type(init_type));
      errorframe_append(&frame, &info);
      errorframe_report(&frame);
      ast_free_unattached(init_type);
      return false;
    }

    ast_free_unattached(init_type);
  }

  ast_settype(ast, type);
  return true;
}
Example #28
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;
}
Example #29
0
// Coerce a literal control block to be the specified target type
static bool coerce_control_block(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);
  assert(lit_type != NULL);
  assert(ast_id(lit_type) == TK_LITERAL);
  ast_t* block_type = ast_type(lit_type);

  for(ast_t* p = ast_child(lit_type); p != NULL; p = ast_sibling(p))
  {
    assert(ast_id(p) == TK_LITERALBRANCH);
    ast_t* branch = (ast_t*)ast_data(p);
    assert(branch != NULL);

    if(!coerce_literal_to_type(&branch, target_type, chain, options,
      report_errors))
    {
      ast_free_unattached(block_type);
      return false;
    }

    block_type = type_union(block_type, ast_type(branch));
  }

  if(is_typecheck_error(block_type))
    return false;

  // block_type may be a sub-tree of the current type of literal_expr.
  // This means we must copy it before setting it as the type since ast_settype
  // will first free the existing type of literal_expr, which may include
  // block_type.
  if(ast_parent(block_type) != NULL)
    block_type = ast_dup(block_type);

  ast_settype(literal_expr, block_type);
  return true;
}
Example #30
0
static bool package_access(pass_opt_t* opt, ast_t** astp)
{
  ast_t* ast = *astp;

  // Left is a packageref, right is an id.
  ast_t* left = ast_child(ast);
  ast_t* right = ast_sibling(left);
  ast_t* type = ast_type(left);

  if(is_typecheck_error(type))
    return false;

  assert(ast_id(left) == TK_PACKAGEREF);
  assert(ast_id(right) == TK_ID);

  // Must be a type in a package.
  const char* package_name = ast_name(ast_child(left));
  ast_t* package = ast_get(left, package_name, NULL);

  if(package == NULL)
  {
    ast_error(right, "can't access package '%s'", package_name);
    return false;
  }

  assert(ast_id(package) == TK_PACKAGE);
  const char* type_name = ast_name(right);
  type = ast_get(package, type_name, NULL);

  if(type == NULL)
  {
    ast_error(right, "can't find type '%s' in package '%s'",
      type_name, package_name);
    return false;
  }

  ast_settype(ast, type_sugar(ast, package_name, type_name));
  ast_setid(ast, TK_TYPEREF);

  return expr_typeref(opt, astp);
}