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

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

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

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

  m->result = add_type(r, result, opt);
}
Example #2
0
static bool is_typeparam_sub_typeparam(ast_t* sub, ast_t* super,
  errorframe_t* errors)
{
  // k <: k'
  // ---
  // A k <: A k'
  ast_t* sub_def = (ast_t*)ast_data(sub);
  ast_t* super_def = (ast_t*)ast_data(super);

  if(sub_def == super_def)
  {
    // We know the bounds on the rcap is the same, so we have different
    // subtyping rules here.
    ast_t* sub_cap = cap_fetch(sub);
    ast_t* sub_eph = ast_sibling(sub_cap);
    ast_t* super_cap = cap_fetch(super);
    ast_t* super_eph = ast_sibling(super_cap);

    if(!is_cap_sub_cap_bound(ast_id(sub_cap), ast_id(sub_eph),
      ast_id(super_cap), ast_id(super_eph)))
    {
      if(errors != NULL)
      {
        ast_error_frame(errors, sub,
          "%s is not a subtype of %s: %s%s is not a subtype of %s%s",
          ast_print_type(sub), ast_print_type(super),
          ast_print_type(sub_cap), ast_print_type(sub_eph),
          ast_print_type(super_cap), ast_print_type(super_eph));
      }

      return false;
    }

    return true;
  }

  if(errors != NULL)
  {
    ast_error_frame(errors, sub,
      "%s is not a subtype of %s: they are different type parameters",
      ast_print_type(sub), ast_print_type(super));
  }

  return false;
}
Example #3
0
File: cap.c Project: DevL/ponyc
token_id cap_single(ast_t* type)
{
  ast_t* cap = cap_fetch(type);
  ast_t* eph = ast_sibling(cap);

  token_id tcap = ast_id(cap);
  token_id teph = ast_id(eph);
  cap_aliasing(&tcap, &teph);

  return tcap;
}
Example #4
0
static bool is_sub_cap_and_eph(ast_t* sub, ast_t* super, errorframe_t* errors)
{
  ast_t* sub_cap = cap_fetch(sub);
  ast_t* sub_eph = ast_sibling(sub_cap);
  ast_t* super_cap = cap_fetch(super);
  ast_t* super_eph = ast_sibling(super_cap);

  if(!is_cap_sub_cap(ast_id(sub_cap), ast_id(sub_eph),
    ast_id(super_cap), ast_id(super_eph)))
  {
    if(errors != NULL)
    {
      ast_error_frame(errors, sub,
        "%s is not a subtype of %s: %s%s is not a subtype of %s%s",
        ast_print_type(sub), ast_print_type(super),
        ast_print_type(sub_cap), ast_print_type(sub_eph),
        ast_print_type(super_cap), ast_print_type(super_eph));
    }

    return false;
  }

  return true;
}
Example #5
0
ast_result_t flatten_typeparamref(pass_opt_t* opt, ast_t* ast)
{
  ast_t* cap_ast = cap_fetch(ast);
  token_id cap = ast_id(cap_ast);

  typeparam_set_cap(ast);

  token_id set_cap = ast_id(cap_ast);

  if((cap != TK_NONE) && (cap != set_cap))
  {
    ast_t* def = (ast_t*)ast_data(ast);
    ast_t* constraint = typeparam_constraint(ast);

    if(constraint != NULL)
    {
      ast_error(opt->check.errors, cap_ast, "can't specify a capability on a "
        "type parameter that differs from the constraint");
      ast_error_continue(opt->check.errors, constraint,
        "constraint definition is here");

      if(ast_parent(constraint) != def)
      {
        ast_error_continue(opt->check.errors, def,
          "type parameter definition is here");
      }
    } else {
      ast_error(opt->check.errors, cap_ast, "a type parameter with no "
        "constraint can only have #any as its capability");
      ast_error_continue(opt->check.errors, def,
        "type parameter definition is here");
    }

    return AST_ERROR;
  }

  return AST_OK;
}
Example #6
0
static void trace_dynamic_nominal(compile_t* c, LLVMValueRef ctx,
  LLVMValueRef object, ast_t* type, ast_t* orig, ast_t* tuple,
  LLVMBasicBlockRef next_block)
{
  pony_assert(ast_id(type) == TK_NOMINAL);

  // Skip if a primitive.
  ast_t* def = (ast_t*)ast_data(type);

  if(ast_id(def) == TK_PRIMITIVE)
    return;

  int mutability = trace_cap_nominal(c->opt, type, orig, tuple);
  // If we can't extract the element from the original type, there is no need to
  // trace the element.
  if(mutability == -1)
    return;

  token_id dst_cap = TK_TAG;
  switch(mutability)
  {
    case PONY_TRACE_MUTABLE:
      dst_cap = TK_ISO;
      break;

    case PONY_TRACE_IMMUTABLE:
      dst_cap = TK_VAL;
      break;

    default: {}
  }

  ast_t* dst_type = ast_dup(type);
  ast_t* dst_cap_ast = cap_fetch(dst_type);
  ast_setid(dst_cap_ast, dst_cap);
  ast_t* dst_eph = ast_sibling(dst_cap_ast);
  if(ast_id(dst_eph) == TK_EPHEMERAL)
    ast_setid(dst_eph, TK_NONE);

  // We aren't always this type. We need to check dynamically.
  LLVMValueRef desc = gendesc_fetch(c, object);
  LLVMValueRef test = gendesc_isnominal(c, desc, type);

  LLVMBasicBlockRef is_true = codegen_block(c, "");
  LLVMBasicBlockRef is_false = codegen_block(c, "");
  LLVMBuildCondBr(c->builder, test, is_true, is_false);

  // Trace as this type.
  LLVMPositionBuilderAtEnd(c->builder, is_true);
  gentrace(c, ctx, object, object, type, dst_type);

  ast_free_unattached(dst_type);

  // If we have traced as mut or val, we're done with this element. Otherwise,
  // continue tracing this as if the match had been unsuccessful.
  if(mutability != PONY_TRACE_OPAQUE)
    LLVMBuildBr(c->builder, next_block);
  else
    LLVMBuildBr(c->builder, is_false);

  // Carry on, whether we have traced or not.
  LLVMPositionBuilderAtEnd(c->builder, is_false);
}
Example #7
0
static int trace_cap_nominal(pass_opt_t* opt, ast_t* type, ast_t* orig,
  ast_t* tuple)
{
  pony_assert(ast_id(type) == TK_NOMINAL);

  ast_t* cap = cap_fetch(type);

  if(tuple != NULL)
  {
    // We are a tuple element. Our type is in the correct position in the
    // tuple, everything else is TK_DONTCARETYPE.
    type = tuple;
  }

  token_id orig_cap = ast_id(cap);

  // We can have a non-sendable rcap if we're tracing a field in a type's trace
  // function. In this case we must always recurse and we have to trace the
  // field as mutable.
  switch(orig_cap)
  {
    case TK_TRN:
    case TK_REF:
    case TK_BOX:
      return PONY_TRACE_MUTABLE;

    default: {}
  }

  // If it's possible to use match or to extract the source type from the
  // destination type with a given cap, then we must trace as this cap. Try iso,
  // val and tag in that order.
  if(orig_cap == TK_ISO)
  {
    if(is_matchtype(orig, type, opt) == MATCHTYPE_ACCEPT)
    {
      return PONY_TRACE_MUTABLE;
    } else {
      ast_setid(cap, TK_VAL);
    }
  }

  if(ast_id(cap) == TK_VAL)
  {
    if(is_matchtype(orig, type, opt) == MATCHTYPE_ACCEPT)
    {
      ast_setid(cap, orig_cap);
      return PONY_TRACE_IMMUTABLE;
    } else {
      ast_setid(cap, TK_TAG);
    }
  }

  pony_assert(ast_id(cap) == TK_TAG);

  int ret = -1;
  if(is_matchtype(orig, type, opt) == MATCHTYPE_ACCEPT)
    ret = PONY_TRACE_OPAQUE;

  ast_setid(cap, orig_cap);
  return ret;
}
Example #8
0
ast_t* viewpoint_lower(ast_t* type)
{
  // T = N | A
  // s = {k}
  // upper(s p'->T k p) = union[k' in s](T (k'->k) eph(s, p', p))
  // eph(s, p', p) = { unalias(p) if p' = ^, exists k in s . k in {iso, trn}
  //                 { p          otherwise
  assert(ast_id(type) == TK_ARROW);
  AST_GET_CHILDREN(type, left, right);
  ast_t* r_right = right;

  switch(ast_id(right))
  {
    case TK_NOMINAL:
    case TK_TYPEPARAMREF:
      break;

    case TK_ARROW:
      // Arrow types are right associative.
      r_right = viewpoint_lower(right);

      if(r_right == NULL)
        return NULL;
      break;

    default:
      assert(0);
      return NULL;
  }

  token_id l_cap = TK_NONE;
  token_id l_eph = TK_NONE;

  switch(ast_id(left))
  {
    case TK_ISO:
    case TK_TRN:
    case TK_REF:
    case TK_VAL:
    case TK_BOX:
    case TK_TAG:
      l_cap = ast_id(left);
      break;

    case TK_THISTYPE:
      l_cap = TK_CAP_READ;
      break;

    case TK_NOMINAL:
    case TK_TYPEPARAMREF:
    {
      ast_t* left_cap = cap_fetch(left);
      ast_t* left_eph = ast_sibling(left_cap);

      l_cap = ast_id(left_cap);
      l_eph = ast_id(left_eph);
      break;
    }

    default:
      assert(0);
      return NULL;
  }

  ast_t* right_cap = cap_fetch(r_right);
  ast_t* right_eph = ast_sibling(right_cap);

  token_id r_cap = ast_id(right_cap);
  token_id r_eph = ast_id(right_eph);

  // No result: left side could be a tag.
  if(!cap_view_lower(l_cap, l_eph, &r_cap, &r_eph))
    return NULL;

  ast_t* rr_right = set_cap_and_ephemeral(r_right, r_cap, r_eph);

  if(r_right != right)
    ast_free_unattached(r_right);

  return rr_right;
}
Example #9
0
ast_t* viewpoint_type(ast_t* l_type, ast_t* r_type)
{
  int upper = VIEW_UPPER_NO;

  switch(ast_id(r_type))
  {
    case TK_UNIONTYPE:
    case TK_ISECTTYPE:
    case TK_TUPLETYPE:
    {
      // Adapt each element.
      ast_t* type = ast_from(r_type, ast_id(r_type));
      ast_t* child = ast_child(r_type);

      while(child != NULL)
      {
        ast_append(type, viewpoint_type(l_type, child));
        child = ast_sibling(child);
      }

      return type;
    }

    case TK_NOMINAL:
    case TK_TYPEPARAMREF:
    {
      ast_t* cap = cap_fetch(r_type);

      switch(ast_id(cap))
      {
        case TK_ISO:
        case TK_TRN:
        case TK_REF:
        case TK_BOX:
        case TK_ISO_BIND:
        case TK_TRN_BIND:
        case TK_REF_BIND:
        case TK_BOX_BIND:
          // A known refcap on the right can be compacted.
          upper = VIEW_UPPER_YES;
          break;

        case TK_VAL:
        case TK_TAG:
        case TK_CAP_SHARE:
        case TK_VAL_BIND:
        case TK_TAG_BIND:
        case TK_CAP_SHARE_BIND:
          // No refcap on the left modifies these.
          upper = VIEW_UPPER_FORCE;
          break;

        default: {}
      }
      break;
    }

    case TK_ARROW:
      break;

    default:
      assert(0);
      return NULL;
  }

  switch(ast_id(l_type))
  {
    case TK_NOMINAL:
    case TK_TYPEPARAMREF:
    {
      ast_t* cap = cap_fetch(l_type);

      switch(ast_id(cap))
      {
        case TK_REF:
        case TK_REF_BIND:
          // ref->T = T
          return ast_dup(r_type);

        case TK_CAP_SEND:
        case TK_CAP_SHARE:
        case TK_CAP_READ:
        case TK_CAP_ALIAS:
        case TK_CAP_ANY:
        case TK_CAP_SEND_BIND:
        case TK_CAP_SHARE_BIND:
        case TK_CAP_READ_BIND:
        case TK_CAP_ALIAS_BIND:
        case TK_CAP_ANY_BIND:
          // Don't compact through an unknown refcap.
          if(upper == VIEW_UPPER_YES)
            upper = VIEW_UPPER_NO;
          break;

        default: {}
      }
      break;
    }

    case TK_THISTYPE:
      if(upper == VIEW_UPPER_YES)
        upper = VIEW_UPPER_NO;
      break;

    case TK_ISO:
    case TK_TRN:
    case TK_REF:
    case TK_VAL:
    case TK_BOX:
    case TK_TAG:
      break;

    case TK_ARROW:
    {
      // (T1->T2)->T3 --> T1->(T2->T3)
      AST_GET_CHILDREN(l_type, left, right);
      ast_t* r_right = viewpoint_type(right, r_type);
      return viewpoint_type(left, r_right);
    }

    default:
      assert(0);
      return NULL;
  }

  BUILD(arrow, l_type,
    NODE(TK_ARROW, TREE(ast_dup(l_type)) TREE(ast_dup(r_type))));

  if(upper != VIEW_UPPER_NO)
  {
    ast_t* arrow_upper = viewpoint_upper(arrow);

    if(arrow_upper == NULL)
      return arrow;

    if(arrow != arrow_upper)
    {
      ast_free_unattached(arrow);
      arrow = arrow_upper;
    }
  }

  return arrow;
}