Ejemplo n.º 1
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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
0
static void syntax_error(parser_t* parser, const char* expected,
  ast_t* ast, const char* terminating)
{
  assert(parser != NULL);
  assert(expected != NULL);
  assert(parser->token != NULL);

  if(parser->last_matched == NULL)
  {
    error(parser->source, token_line_number(parser->token),
      token_line_position(parser->token), "syntax error: no code found");
  }
  else
  {
    if(terminating == NULL)
    {
      error(parser->source, token_line_number(parser->token),
        token_line_position(parser->token),
        "syntax error: expected %s after %s", expected, parser->last_matched);
    }
    else
    {
      assert(ast != NULL);
      errorframe_t frame = NULL;
      ast_error_frame(&frame, ast, "syntax error: unterminated %s",
        terminating);
      errorframe(&frame, parser->source, token_line_number(parser->token),
        token_line_position(parser->token),
        "expected terminating %s before here", expected);
      errorframe_report(&frame);
    }
  }
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
bool expr_break(pass_opt_t* opt, ast_t* ast)
{
  typecheck_t* t = &opt->check;

  if(t->frame->loop_body == NULL)
  {
    ast_error(opt->check.errors, ast, "must be in a loop");
    return false;
  }

  errorframe_t errorf = NULL;
  if(!ast_all_consumes_in_scope(t->frame->loop_body, ast, &errorf))
  {
    errorframe_report(&errorf, opt->check.errors);
    return false;
  }

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

  ast_settype(ast, ast_from(ast, TK_BREAK));

  // Add type to loop.
  ast_t* body = ast_child(ast);

  if(ast_id(body) != TK_NONE)
  {
    if(is_control_type(ast_type(body)))
    {
      ast_error(opt->check.errors, body,
        "break value cannot be a control statement");
      return false;
    }

    ast_t* loop_type = ast_type(t->frame->loop);

    // If there is no body the break will jump to the else branch, whose type
    // has already been added to the loop type.
    loop_type = control_type_add_branch(opt, loop_type, body);
    ast_settype(t->frame->loop, loop_type);
  }

  return true;
}
Ejemplo n.º 6
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;
}
Ejemplo n.º 7
0
static bool check_return_type(ast_t* ast)
{
  AST_GET_CHILDREN(ast, cap, id, typeparams, params, type, can_error, body);
  ast_t* body_type = ast_type(body);

  if(is_typecheck_error(body_type))
    return false;

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

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

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

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

  ast_free_unattached(a_type);
  ast_free_unattached(a_body_type);
  return ok;
}
Ejemplo n.º 8
0
bool expr_provides(pass_opt_t* opt, ast_t* ast)
{
  // Check that the type actually provides everything it declares.
  // Since the traits pass has completed, all method imports have already
  // happened. At this point, we need to check that the type is a structural
  // subtype of all traits and interfaces it declares as provided.
  AST_GET_CHILDREN(ast, id, typeparams, cap, provides);
  ast_t* type = type_for_this(opt, ast, TK_REF, TK_NONE, true);
  errorframe_t err = NULL;

  if(!check_provides(opt, type, provides, &err))
  {
    errorframe_t err2 = NULL;
    ast_error_frame(&err2, ast, "type does not implement its provides list");
    errorframe_append(&err2, &err);
    errorframe_report(&err2, opt->check.errors);
    return false;
  }

  return true;
}
Ejemplo n.º 9
0
bool expr_continue(pass_opt_t* opt, ast_t* ast)
{
  typecheck_t* t = &opt->check;

  if(t->frame->loop_body == NULL)
  {
    ast_error(opt->check.errors, ast, "must be in a loop");
    return false;
  }

  errorframe_t errorf = NULL;
  if(!ast_all_consumes_in_scope(t->frame->loop_body, ast, &errorf))
  {
    errorframe_report(&errorf, opt->check.errors);
    return false;
  }

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

  ast_settype(ast, ast_from(ast, TK_CONTINUE));
  return true;
}
Ejemplo n.º 10
0
bool expr_field(pass_opt_t* opt, ast_t* ast)
{
  AST_GET_CHILDREN(ast, id, type, init, delegates);
  bool ok = true;

  for(ast_t* del = ast_child(delegates); del != NULL; del = ast_sibling(del))
  {
    errorframe_t err = NULL;

    if(!is_subtype(type, del, &err, opt))
    {
      errorframe_t err2 = NULL;
      ast_error_frame(&err2, ast, "field not a subtype of delegate");
      errorframe_append(&err2, &err);
      errorframe_report(&err2, opt->check.errors);
      ok = false;
    }
  }

  if(ok)
    ast_settype(ast, type);

  return ok;
}
Ejemplo n.º 11
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(opt->check.errors, pattern, "not a matchable pattern");
    return false;
  }

  switch(ast_id(pattern))
  {
    case TK_MATCH_CAPTURE:
      // Captures are always OK.
      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:
      if(ast_childcount(pattern) == 1)  // This may be a just a capture.
        return is_valid_pattern(opt, ast_child(pattern));

      // Treat this like other nodes.
      break;

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

    default:
      break;
  }

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

  if(fun == NULL)
  {
    ast_error(opt->check.errors, pattern,
      "this pattern element doesn't support structural equality");

    return false;
  }

  if(ast_id(fun) != TK_FUN)
  {
    ast_error(opt->check.errors, pattern,
      "eq is not a function on this pattern element");
    ast_error_continue(opt->check.errors, 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(opt->check.errors, pattern,
      "polymorphic eq not supported in pattern matching");
    ok = false;
  }

  if(!is_bool(result))
  {
    ast_error(opt->check.errors, pattern,
      "eq must return Bool when pattern matching");
    ok = false;
  }

  if(ast_id(partial) != TK_NONE)
  {
    ast_error(opt->check.errors, pattern,
      "eq cannot be partial when pattern matching");
    ok = false;
  }

  ast_t* r_type = set_cap_and_ephemeral(pattern_type, ast_id(cap), TK_NONE);
  ast_t* a_type = alias(pattern_type);
  errorframe_t info = NULL;

  if(!is_subtype(a_type, r_type, &info, opt))
  {
    errorframe_t frame = NULL;
    ast_error_frame(&frame, pattern, "eq cannot be called on this pattern");
    errorframe_append(&frame, &info);
    errorframe_report(&frame, opt->check.errors);
    ok = false;
  }

  ast_t* param = ast_child(params);

  if(param == NULL || ast_sibling(param) != NULL)
  {
    ast_error(opt->check.errors, 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(r_type);
  ast_free_unattached(a_type);
  ast_free_unattached(fun);
  return ok;
}
Ejemplo n.º 12
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(opt->check.errors, ast, "can't read a field through %s",
        ast_print_type(l_type));
      return false;
    }

    ast_free_unattached(upper);
  }

  // In a recover expression, we can access obj.field if field is sendable
  // and not being assigned to, even if obj isn't sendable.

  typecheck_t* t = &opt->check;

  if(t->frame->recover != NULL)
  {
    if(!sendable(type))
    {
      if(!sendable(l_type))
      {
        errorframe_t frame = NULL;
        ast_error_frame(&frame, ast, "can't access field of non-sendable "
          "object inside of a recover expression");
        ast_error_frame(&frame, find, "this would be possible if the field was "
          "sendable");
        errorframe_report(&frame, opt->check.errors);
        return false;
      }
    }
    else
    {
      ast_t* parent = ast_parent(ast);
      ast_t* current = ast;
      while(ast_id(parent) != TK_RECOVER && ast_id(parent) != TK_ASSIGN)
      {
        current = parent;
        parent = ast_parent(parent);
      }
      if(ast_id(parent) == TK_ASSIGN && ast_child(parent) != current)
      {
        errorframe_t frame = NULL;
        ast_error_frame(&frame, ast, "can't access field of non-sendable "
          "object inside of a recover expression");
        ast_error_frame(&frame, parent, "this would be possible if the field "
          "wasn't assigned to");
        errorframe_report(&frame, opt->check.errors);
        return false;
      }
    }
  }

  // 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'.
    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;
}
Ejemplo n.º 13
0
static bool check_receiver_cap(pass_opt_t* opt, ast_t* ast, bool incomplete)
{
  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);

  // Check receiver cap.
  ast_t* receiver = ast_child(lhs);

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

  // Receiver type, alias of receiver type, and target type.
  ast_t* r_type = ast_type(receiver);

  if(is_typecheck_error(r_type))
    return false;

  ast_t* t_type = set_cap_and_ephemeral(r_type, ast_id(cap), TK_NONE);
  ast_t* a_type;

  // If we can recover the receiver, we don't alias it here.
  bool can_recover = auto_recover_call(ast, r_type, positional, result);
  bool cap_recover = false;

  switch(ast_id(cap))
  {
    case TK_ISO:
    case TK_TRN:
    case TK_VAL:
    case TK_TAG:
      break;

    case TK_REF:
    case TK_BOX:
      cap_recover = true;
      break;

    default:
      assert(0);
  }

  if(can_recover && cap_recover)
    a_type = r_type;
  else
    a_type = alias(r_type);

  if(incomplete && (ast_id(receiver) == TK_THIS))
  {
    // If 'this' is incomplete and the arg is 'this', change the type to tag.
    ast_t* tag_type = set_cap_and_ephemeral(a_type, TK_TAG, TK_NONE);

    if(a_type != r_type)
      ast_free_unattached(a_type);

    a_type = tag_type;
  } else {
    incomplete = false;
  }

  errorframe_t info = NULL;
  bool ok = is_subtype(a_type, t_type, &info, opt);

  if(!ok)
  {
    errorframe_t frame = NULL;

    ast_error_frame(&frame, ast,
      "receiver type is not a subtype of target type");
    ast_error_frame(&frame, receiver,
      "receiver type: %s", ast_print_type(a_type));
    ast_error_frame(&frame, cap,
      "target type: %s", ast_print_type(t_type));

    if(!can_recover && cap_recover && is_subtype(r_type, t_type, NULL, opt))
    {
      ast_error_frame(&frame, ast,
        "this would be possible if the arguments and return value "
        "were all sendable");
    }

    if(incomplete && is_subtype(r_type, t_type, NULL, opt))
    {
      ast_error_frame(&frame, ast,
        "this would be possible if all the fields of 'this' were assigned to "
        "at this point");
    }

    errorframe_append(&frame, &info);
    errorframe_report(&frame, opt->check.errors);
  }

  if(a_type != r_type)
    ast_free_unattached(a_type);

  ast_free_unattached(r_type);
  ast_free_unattached(t_type);
  return ok;
}
Ejemplo n.º 14
0
Archivo: reify.c Proyecto: DevL/ponyc
bool check_constraints(ast_t* orig, ast_t* typeparams, ast_t* typeargs,
  bool report_errors)
{
  ast_t* typeparam = ast_child(typeparams);
  ast_t* typearg = ast_child(typeargs);

  while(typeparam != NULL)
  {
    // Reify the constraint.
    ast_t* constraint = ast_childidx(typeparam, 1);
    ast_t* bind_constraint = bind_type(constraint);
    ast_t* r_constraint = reify(bind_constraint, typeparams, typeargs);

    if(bind_constraint != r_constraint)
      ast_free_unattached(bind_constraint);

    // A bound type must be a subtype of the constraint.
    errorframe_t info = NULL;
    if(!is_subtype(typearg, r_constraint, report_errors ? &info : NULL))
    {
      if(report_errors)
      {
        errorframe_t frame = NULL;
        ast_error_frame(&frame, orig,
          "type argument is outside its constraint");
        ast_error_frame(&frame, typearg,
          "argument: %s", ast_print_type(typearg));
        ast_error_frame(&frame, typeparam,
          "constraint: %s", ast_print_type(r_constraint));
        errorframe_append(&frame, &info);
        errorframe_report(&frame);
      }

      ast_free_unattached(r_constraint);
      return false;
    }

    ast_free_unattached(r_constraint);

    // A constructable constraint can only be fulfilled by a concrete typearg.
    if(is_constructable(constraint) && !is_concrete(typearg))
    {
      if(report_errors)
      {
        ast_error(orig, "a constructable constraint can only be fulfilled "
          "by a concrete type argument");
        ast_error(typearg, "argument: %s", ast_print_type(typearg));
        ast_error(typeparam, "constraint: %s", ast_print_type(constraint));
      }

      return false;
    }

    typeparam = ast_sibling(typeparam);
    typearg = ast_sibling(typearg);
  }

  assert(typeparam == NULL);
  assert(typearg == NULL);
  return true;
}
Ejemplo n.º 15
0
static bool check_arg_types(pass_opt_t* opt, ast_t* params, ast_t* positional,
  bool incomplete, bool partial)
{
  // Check positional args vs params.
  ast_t* param = ast_child(params);
  ast_t* arg = ast_child(positional);

  while(arg != NULL)
  {
    if(ast_id(arg) == TK_NONE)
    {
      if(partial)
      {
        // Don't check missing arguments for partial application.
        arg = ast_sibling(arg);
        param = ast_sibling(param);
        continue;
      } else {
        // Pick up a default argument if we can.
        if(!apply_default_arg(opt, param, arg))
          return false;
      }
    }

    ast_t* p_type = ast_childidx(param, 1);

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

    ast_t* arg_type = ast_type(arg);

    if(is_typecheck_error(arg_type))
      return false;

    if(is_control_type(arg_type))
    {
      ast_error(opt->check.errors, arg,
        "can't use a control expression in an argument");
      return false;
    }

    ast_t* a_type = alias(arg_type);

    if(incomplete)
    {
      ast_t* expr = arg;

      if(ast_id(arg) == TK_SEQ)
        expr = ast_child(arg);

      // If 'this' is incomplete and the arg is 'this', change the type to tag.
      if((ast_id(expr) == TK_THIS) && (ast_sibling(expr) == NULL))
      {
        ast_t* tag_type = set_cap_and_ephemeral(a_type, TK_TAG, TK_NONE);
        ast_free_unattached(a_type);
        a_type = tag_type;
      }
    }

    errorframe_t info = NULL;
    if(!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);
      ast_free_unattached(a_type);
      return false;
    }

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

  return true;
}
Ejemplo n.º 16
0
bool expr_return(pass_opt_t* opt, ast_t* ast)
{
  typecheck_t* t = &opt->check;

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

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

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

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

  ast_t* body_type = ast_type(body);

  if(is_typecheck_error(body_type))
    return false;

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

  bool ok = true;

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

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

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

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

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

  ast_settype(ast, ast_from(ast, TK_RETURN));
  ast_inheritflags(ast);
  return ok;
}
Ejemplo n.º 17
0
bool check_constraints(ast_t* orig, ast_t* typeparams, ast_t* typeargs,
  bool report_errors, pass_opt_t* opt)
{
  ast_t* typeparam = ast_child(typeparams);
  ast_t* typearg = ast_child(typeargs);

  while(typeparam != NULL)
  {
    if(is_bare(typearg))
    {
      if(report_errors)
      {
        ast_error(opt->check.errors, typearg,
          "a bare type cannot be used as a type argument");
      }

      return false;
    }

    switch(ast_id(typearg))
    {
      case TK_NOMINAL:
      {
        ast_t* def = (ast_t*)ast_data(typearg);

        if(ast_id(def) == TK_STRUCT)
        {
          if(report_errors)
          {
            ast_error(opt->check.errors, typearg,
              "a struct cannot be used as a type argument");
          }

          return false;
        }
        break;
      }

      case TK_TYPEPARAMREF:
      {
        ast_t* def = (ast_t*)ast_data(typearg);

        if(def == typeparam)
        {
          typeparam = ast_sibling(typeparam);
          typearg = ast_sibling(typearg);
          continue;
        }
        break;
      }

      default: {}
    }

    // Reify the constraint.
    ast_t* constraint = ast_childidx(typeparam, 1);
    ast_t* r_constraint = reify(constraint, typeparams, typeargs, opt,
      true);

    // A bound type must be a subtype of the constraint.
    errorframe_t info = NULL;
    errorframe_t* infop = (report_errors ? &info : NULL);
    if(!is_subtype_constraint(typearg, r_constraint, infop, opt))
    {
      if(report_errors)
      {
        errorframe_t frame = NULL;
        ast_error_frame(&frame, orig,
          "type argument is outside its constraint");
        ast_error_frame(&frame, typearg,
          "argument: %s", ast_print_type(typearg));
        ast_error_frame(&frame, typeparam,
          "constraint: %s", ast_print_type(r_constraint));
        errorframe_append(&frame, &info);
        errorframe_report(&frame, opt->check.errors);
      }

      ast_free_unattached(r_constraint);
      return false;
    }

    ast_free_unattached(r_constraint);

    // A constructable constraint can only be fulfilled by a concrete typearg.
    if(is_constructable(constraint) && !is_concrete(typearg))
    {
      if(report_errors)
      {
        ast_error(opt->check.errors, orig, "a constructable constraint can "
          "only be fulfilled by a concrete type argument");
        ast_error_continue(opt->check.errors, typearg, "argument: %s",
          ast_print_type(typearg));
        ast_error_continue(opt->check.errors, typeparam, "constraint: %s",
          ast_print_type(constraint));
      }

      return false;
    }

    typeparam = ast_sibling(typeparam);
    typearg = ast_sibling(typearg);
  }

  pony_assert(typeparam == NULL);
  pony_assert(typearg == NULL);
  return true;
}
Ejemplo n.º 18
0
static bool check_receiver_cap(pass_opt_t* opt, ast_t* ast, bool* recovered)
{
  AST_GET_CHILDREN(ast, positional, namedargs, question, lhs);

  ast_t* type = ast_type(lhs);

  if(is_typecheck_error(type))
    return false;

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

  // Receiver type, alias of receiver type, and target type.
  ast_t* r_type = method_receiver_type(lhs);

  if(is_typecheck_error(r_type))
    return false;

  ast_t* t_type = set_cap_and_ephemeral(r_type, ast_id(cap), TK_NONE);
  ast_t* a_type;

  // If we can recover the receiver, we don't alias it here.
  bool can_recover = auto_recover_call(lhs, r_type, positional, result);
  bool cap_recover = false;

  switch(ast_id(cap))
  {
    case TK_ISO:
    case TK_TRN:
    case TK_VAL:
    case TK_TAG:
      break;

    case TK_REF:
    case TK_BOX:
      cap_recover = true;
      break;

    default:
      pony_assert(0);
  }

  if(can_recover && cap_recover)
  {
    a_type = r_type;
    if(recovered != NULL)
      *recovered = true;
  }
  else
  {
    a_type = alias(r_type);
    if(recovered != NULL)
      *recovered = false;
  }

  errorframe_t info = NULL;
  bool ok = is_subtype(a_type, t_type, &info, opt);

  if(!ok)
  {
    errorframe_t frame = NULL;

    ast_error_frame(&frame, ast,
      "receiver type is not a subtype of target type");
    ast_error_frame(&frame, ast_child(lhs),
      "receiver type: %s", ast_print_type(a_type));
    ast_error_frame(&frame, cap,
      "target type: %s", ast_print_type(t_type));
    errorframe_append(&frame, &info);

    if(ast_checkflag(ast_type(method_receiver(lhs)), AST_FLAG_INCOMPLETE))
      ast_error_frame(&frame, method_receiver(lhs),
        "this might be possible if all fields were already defined");

    if(!can_recover && cap_recover && is_subtype(r_type, t_type, NULL, opt))
    {
      ast_error_frame(&frame, ast,
        "this would be possible if the arguments and return value "
        "were all sendable");
    }

    errorframe_report(&frame, opt->check.errors);
  }

  if(a_type != r_type)
    ast_free_unattached(a_type);

  ast_free_unattached(r_type);
  ast_free_unattached(t_type);
  return ok;
}
Ejemplo n.º 19
0
static bool check_arg_types(pass_opt_t* opt, ast_t* params, ast_t* positional,
  bool partial)
{
  // Check positional args vs params.
  ast_t* param = ast_child(params);
  ast_t* arg = ast_child(positional);

  while(arg != NULL)
  {
    if(ast_id(arg) == TK_NONE)
    {
      if(partial)
      {
        // Don't check missing arguments for partial application.
        arg = ast_sibling(arg);
        param = ast_sibling(param);
        continue;
      } else {
        // Pick up a default argument if we can.
        if(!apply_default_arg(opt, param, arg))
          return false;
      }
    }

    ast_t* p_type = ast_childidx(param, 1);

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

    ast_t* arg_type = ast_type(arg);

    if(is_typecheck_error(arg_type))
      return false;

    if(ast_checkflag(arg, AST_FLAG_JUMPS_AWAY))
    {
      ast_error(opt->check.errors, arg,
        "can't use a control expression in an argument");
      return false;
    }

    ast_t* a_type = alias(arg_type);
    errorframe_t info = NULL;

    if(!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);

      if(ast_checkflag(ast_type(arg), AST_FLAG_INCOMPLETE))
        ast_error_frame(&frame, arg,
          "this might be possible if all fields were already defined");

      errorframe_report(&frame, opt->check.errors);
      ast_free_unattached(a_type);
      return false;
    }

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

  return true;
}
Ejemplo n.º 20
0
static ast_result_t declared_ffi(pass_opt_t* opt, ast_t* call, ast_t* decl)
{
  assert(call != NULL);
  assert(decl != NULL);
  assert(ast_id(decl) == TK_FFIDECL);

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

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

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

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

    ast_t* a_type = ast_type(arg);

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

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

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

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

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

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

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

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

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

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

  // Store the declaration so that codegen can generate a non-variadic
  // signature for the FFI call.
  ast_setdata(call, decl);
  ast_settype(call, decl_ret_type);
  ast_inheritflags(call);
  return AST_OK;
}
Ejemplo n.º 21
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(l_type == NULL || !is_lvalue(opt, left, is_result_needed(ast)))
  {
    ast_error(opt->check.errors, ast,
      "left side must be something that can be assigned to");
    return false;
  }

  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(is_control_type(r_type))
  {
    ast_error(opt->check.errors, ast,
      "the right hand side does not return a value");
    return false;
  }

  if(!infer_locals(opt, 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);

  errorframe_t info = NULL;
  if(!is_subtype(a_type, l_type, &info, opt))
  {
    errorframe_t frame = NULL;
    ast_error_frame(&frame, ast, "right side must be a subtype of left side");
    errorframe_append(&frame, &info);
    errorframe_report(&frame, opt->check.errors);
    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(opt->check.errors, ast,
          "can't destructure a union using assignment, use pattern matching "
          "instead");
        break;

      case TK_ISECTTYPE:
        ast_error(opt->check.errors, ast,
          "can't destructure an intersection using assignment, use pattern "
          "matching instead");
        break;

      default:
        assert(0);
        break;
    }

    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(opt->check.errors, 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(opt->check.errors, ast,
      "not safe to write right side to left side");
    ast_error_continue(opt->check.errors, a_type, "right side type: %s",
      ast_print_type(a_type));
    ast_free_unattached(a_type);
    return false;
  }

  ast_free_unattached(a_type);

  if(!check_embed_construction(opt, left, right))
    return false;

  ast_settype(ast, consume_type(l_type, TK_NONE));
  return true;
}
Ejemplo n.º 22
0
// Process the given capture and create the AST for the corresponding field.
// Returns the create field AST in out_field, which must be freed by the caller,
// or NULL if there is no field to create.
// Returns false on error.
static bool make_capture_field(pass_opt_t* opt, ast_t* capture,
  ast_t** out_field)
{
  pony_assert(capture != NULL);
  pony_assert(out_field != NULL);

  AST_GET_CHILDREN(capture, id_node, type, value);
  const char* name = ast_name(id_node);

  bool is_dontcare = is_name_dontcare(name);

  // There are 3 varieties of capture:
  // x -> capture variable x, type from defn of x
  // x = y -> capture expression y, type inferred from expression type
  // x: T = y -> capture expression y, type T

  if(ast_id(value) == TK_NONE)
  {
    // Variable capture
    pony_assert(ast_id(type) == TK_NONE);

    if(is_dontcare)
    {
      *out_field = NULL;
      return true;
    }

    ast_t* def = ast_get(capture, name, NULL);

    if(def == NULL)
    {
      ast_error(opt->check.errors, id_node,
        "cannot capture \"%s\", variable not defined", name);
      return false;
    }

    // lambda captures used before their declaration with their type
    // not defined are not legal
    if(!def_before_use(opt, def, capture, name))
      return false;

    switch(ast_id(def))
    {
      case TK_VAR:
      case TK_LET:
      case TK_PARAM:
      case TK_MATCH_CAPTURE:
      case TK_FVAR:
      case TK_FLET:
      case TK_EMBED:
        break;

      default:
        ast_error(opt->check.errors, id_node, "cannot capture \"%s\", can only "
          "capture fields, parameters and local variables", name);
        return false;
    }

    BUILD(capture_rhs, id_node, NODE(TK_REFERENCE, ID(name)));

    type = alias(ast_type(def));
    value = capture_rhs;
  } else if(ast_id(type) == TK_NONE) {
    // No type specified, use type of the captured expression
    if(ast_type(value) == NULL)
      return false;

    type = alias(ast_type(value));
  } else {
    // Type given, infer literals
    if(!coerce_literals(&value, type, opt))
      return false;

    // Check subtyping now if we're capturing into '_', since the field will be
    // discarded.
    if(is_dontcare)
    {
      ast_t* v_type = alias(ast_type(value));
      errorframe_t info = NULL;

      if(!is_subtype(v_type, type, &info, opt))
      {
        errorframe_t frame = NULL;
        ast_error_frame(&frame, value, "argument not a subtype of parameter");
        errorframe_append(&frame, &info);
        errorframe_report(&frame, opt->check.errors);
        ast_free_unattached(v_type);
        return false;
      }

      ast_free_unattached(v_type);
    }
  }

  if(is_typecheck_error(type))
    return false;

  if(is_dontcare)
  {
    *out_field = NULL;
    return true;
  }

  type = sanitise_type(type);

  BUILD(field, id_node,
    NODE(TK_FVAR,
      TREE(id_node)
      TREE(type)
      TREE(value)));

  *out_field = field;
  return true;
}