Exemple #1
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)
{
  // Skip if a primitive.
  ast_t* def = (ast_t*)ast_data(type);

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

  // If it's not possible to use match or as to extract this type from the
  // original type, there's no need to trace as this type.
  if(tuple != NULL)
  {
    // We are a tuple element. Our type is in the correct position in the
    // tuple, everything else is TK_DONTCARE.
    if(is_matchtype(orig, tuple) != MATCHTYPE_ACCEPT)
      return;
  } else {
    // We aren't a tuple element.
    if(is_matchtype(orig, type) != MATCHTYPE_ACCEPT)
      return;
  }

  // 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, type);

  // If we have traced as known, unknown or actor, we're done with this
  // element. Otherwise, continue tracing this as if the match had been
  // unsuccessful.
  switch(trace_type(type))
  {
    case TRACE_KNOWN:
    case TRACE_UNKNOWN:
    case TRACE_KNOWN_VAL:
    case TRACE_UNKNOWN_VAL:
    case TRACE_ACTOR:
      LLVMBuildBr(c->builder, next_block);
      break;

    default:
      LLVMBuildBr(c->builder, is_false);
      break;
  }

  // Carry on, whether we have traced or not.
  LLVMPositionBuilderAtEnd(c->builder, is_false);
}
Exemple #2
0
static matchtype_t is_x_match_isect(ast_t* operand, ast_t* pattern)
{
  matchtype_t ok = MATCHTYPE_ACCEPT;

  for(ast_t* child = ast_child(pattern);
    child != NULL;
    child = ast_sibling(child))
  {
    switch(is_matchtype(operand, child))
    {
      case MATCHTYPE_ACCEPT:
        break;

      case MATCHTYPE_REJECT:
        // If any type in the pattern isect rejects a match, the entire pattern
        // isect rejects a match.
        ok = MATCHTYPE_REJECT;
        break;

      case MATCHTYPE_DENY:
        // If any type in the pattern isect denies a match, the entire pattern
        // isect denies a match.
        return MATCHTYPE_DENY;
    }
  }

  return ok;
}
Exemple #3
0
static matchtype_t is_tuple_match_tuple(ast_t* operand, ast_t* pattern)
{
  // Must be a pairwise match.
  if(ast_childcount(operand) != ast_childcount(pattern))
    return MATCHTYPE_REJECT;

  ast_t* operand_child = ast_child(operand);
  ast_t* pattern_child = ast_child(pattern);
  matchtype_t ok = MATCHTYPE_ACCEPT;

  while(operand_child != NULL)
  {
    switch(is_matchtype(operand_child, pattern_child))
    {
      case MATCHTYPE_ACCEPT:
        break;

      case MATCHTYPE_REJECT:
        ok = MATCHTYPE_REJECT;
        break;

      case MATCHTYPE_DENY:
        return MATCHTYPE_DENY;
    }

    operand_child = ast_sibling(operand_child);
    pattern_child = ast_sibling(pattern_child);
  }

  return ok;
}
Exemple #4
0
static matchtype_t is_union_match_x(ast_t* operand, ast_t* pattern)
{
  matchtype_t ok = MATCHTYPE_REJECT;

  for(ast_t* child = ast_child(operand);
    child != NULL;
    child = ast_sibling(child))
  {
    switch(is_matchtype(child, pattern))
    {
      case MATCHTYPE_ACCEPT:
        // If any type in the operand union accepts a match, then the entire
        // operand union accepts a match.
        ok = MATCHTYPE_ACCEPT;
        break;

      case MATCHTYPE_REJECT:
        break;

      case MATCHTYPE_DENY:
        // If any type in the operand union denies a match, then the entire
        // operand union is denied a match.
        return MATCHTYPE_DENY;
    }
  }

  return ok;
}
Exemple #5
0
static matchtype_t is_x_match_arrow(ast_t* operand, ast_t* pattern)
{
  // T1 match upperbound(T2->T3)
  // ---
  // T1 match T2->T3
  ast_t* pattern_upper = viewpoint_upper(pattern);
  matchtype_t ok = is_matchtype(operand, pattern_upper);
  ast_free_unattached(pattern_upper);
  return ok;
}
Exemple #6
0
static matchtype_t is_arrow_match_nominal(ast_t* operand, ast_t* pattern)
{
  // lowerbound(T1->T2) match T3
  // ---
  // (T1->T2) match T3
  ast_t* operand_lower = viewpoint_lower(operand);
  matchtype_t ok = is_matchtype(operand_lower, pattern);
  ast_free_unattached(operand_lower);
  return ok;
}
Exemple #7
0
static matchtype_t is_x_match_typeparam(ast_t* operand, ast_t* pattern)
{
  ast_t* pattern_upper = typeparam_upper(pattern);

  // An unconstrained typeparam can match anything.
  if(pattern_upper == NULL)
    return MATCHTYPE_ACCEPT;

  // Otherwise, match the constraint.
  matchtype_t ok = is_matchtype(operand, pattern_upper);
  ast_free_unattached(pattern_upper);
  return ok;
}
Exemple #8
0
static matchtype_t is_typeparam_match_x(ast_t* operand, ast_t* pattern)
{
  ast_t* operand_upper = typeparam_upper(operand);

  // An unconstrained typeparam could match anything.
  if(operand_upper == NULL)
    return MATCHTYPE_ACCEPT;

  // Check if the constraint can match the pattern.
  matchtype_t ok = is_matchtype(operand_upper, pattern);
  ast_free_unattached(operand_upper);
  return ok;
}
Exemple #9
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(pattern);
    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;
}
Exemple #10
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;
}
Exemple #11
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;
}