Esempio n. 1
0
File: control.c Progetto: 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;
}
Esempio n. 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;
}
Esempio n. 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;
}
Esempio n. 4
0
File: control.c Progetto: ozra/ponyc
bool expr_break(typecheck_t* t, ast_t* ast)
{
    if(t->frame->loop_body == NULL)
    {
        ast_error(ast, "must be in a loop");
        return false;
    }

    if(!ast_all_consumes_in_scope(t->frame->loop_body, ast))
        return false;

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

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

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

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

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

    loop_type = control_type_add_branch(loop_type, body);
    ast_settype(t->frame->loop, loop_type);

    return true;
}
Esempio 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;
}
Esempio n. 6
0
bool expr_tuple(pass_opt_t* opt, ast_t* ast)
{
  ast_t* child = ast_child(ast);
  ast_t* type;

  if(ast_sibling(child) == NULL)
  {
    type = ast_type(child);
  } else {
    type = ast_from(ast, TK_TUPLETYPE);

    while(child != NULL)
    {
      ast_t* c_type = ast_type(child);

      if(c_type == NULL)
        return false;

      if(is_control_type(c_type))
      {
        ast_error(opt->check.errors, child,
          "a tuple can't contain a control flow expression");
        return false;
      }

      if(is_type_literal(c_type))
      {
        // At least one tuple member is literal, so whole tuple is
        ast_free(type);
        make_literal_type(ast);
        ast_inheritflags(ast);
        return true;
      }

      ast_append(type, c_type);
      child = ast_sibling(child);
    }
  }

  ast_settype(ast, type);
  ast_inheritflags(ast);
  return true;
}
Esempio 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;
}
Esempio n. 8
0
File: match.c Progetto: mgist/ponyc
bool expr_cases(ast_t* ast)
{
  assert(ast_id(ast) == TK_CASES);
  ast_t* the_case = ast_child(ast);

  if(the_case == NULL)
  {
    ast_error(ast, "match must have at least one case");
    return false;
  }

  ast_t* type = NULL;
  size_t branch_count = 0;

  while(the_case != NULL)
  {
    AST_GET_CHILDREN(the_case, pattern, guard, body);
    ast_t* body_type = ast_type(body);

    if(!is_typecheck_error(body_type) && !is_control_type(body_type))
    {
      type = control_type_add_branch(type, body);
      ast_inheritbranch(ast, the_case);
      branch_count++;
    }

    the_case = ast_sibling(the_case);
  }

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

  ast_settype(ast, type);
  ast_inheritflags(ast);
  ast_consolidate_branches(ast, branch_count);
  return true;
}
Esempio n. 9
0
LLVMValueRef gen_while(compile_t* c, ast_t* ast)
{
  bool needed = is_result_needed(ast);
  AST_GET_CHILDREN(ast, cond, body, else_clause);

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

  reach_type_t* phi_type = NULL;

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

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

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

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

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

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

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

  if(i_value == NULL)
    return NULL;

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

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

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

  if(l_value == NULL)
    return NULL;

  LLVMBasicBlockRef body_from = NULL;

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

    if(c_value == NULL)
      return NULL;

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

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

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

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

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

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

  if(is_control_type(type))
    return GEN_NOVALUE;

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

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

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

    return phi;
  }

  return GEN_NOTNEEDED;
}
Esempio n. 10
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;
}
Esempio n. 11
0
static void reachable_expr(reach_t* r, ast_t* ast, pass_opt_t* opt)
{
  // If this is a method call, mark the method as reachable.
  switch(ast_id(ast))
  {
    case TK_TRUE:
    case TK_FALSE:
    case TK_INT:
    case TK_FLOAT:
    case TK_STRING:
    {
      ast_t* type = ast_type(ast);

      if(type != NULL)
        reachable_method(r, type, stringtab("create"), NULL, opt);
      break;
    }

    case TK_LET:
    case TK_VAR:
    case TK_TUPLE:
    {
      ast_t* type = ast_type(ast);
      add_type(r, type, opt);
      break;
    }

    case TK_CASE:
    {
      AST_GET_CHILDREN(ast, pattern, guard, body);
      reachable_pattern(r, pattern, opt);
      reachable_expr(r, guard, opt);
      reachable_expr(r, body, opt);
      break;
    }

    case TK_CALL:
      reachable_call(r, ast, opt);
      break;

    case TK_FFICALL:
      reachable_ffi(r, ast, opt);
      break;

    case TK_ADDRESS:
      reachable_addressof(r, ast, opt);
      break;

    case TK_IF:
    {
      AST_GET_CHILDREN(ast, cond, then_clause, else_clause);
      assert(ast_id(cond) == TK_SEQ);
      cond = ast_child(cond);

      ast_t* type = ast_type(ast);

      if(is_result_needed(ast) && !is_control_type(type))
        add_type(r, type, opt);

      if(ast_sibling(cond) == NULL)
      {
        if(ast_id(cond) == TK_TRUE)
        {
          reachable_expr(r, then_clause, opt);
          return;
        } else if(ast_id(cond) == TK_FALSE) {
          reachable_expr(r, else_clause, opt);
          return;
        }
      }
      break;
    }

    case TK_MATCH:
    case TK_WHILE:
    case TK_REPEAT:
    case TK_TRY:
    {
      ast_t* type = ast_type(ast);

      if(is_result_needed(ast) && !is_control_type(type))
        add_type(r, type, opt);

      break;
    }

    default: {}
  }

  // Traverse all child expressions looking for calls.
  ast_t* child = ast_child(ast);

  while(child != NULL)
  {
    reachable_expr(r, child, opt);
    child = ast_sibling(child);
  }
}
Esempio n. 12
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;
}
Esempio n. 13
0
LLVMValueRef gen_repeat(compile_t* c, ast_t* ast)
{
  bool needed = is_result_needed(ast);
  AST_GET_CHILDREN(ast, body, cond, else_clause);

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

  reach_type_t* phi_type = NULL;

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

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

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

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

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

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

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

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

  if(value == NULL)
    return NULL;

  LLVMBasicBlockRef body_from = NULL;

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

    if(c_value == NULL)
      return NULL;

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

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

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

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

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

  if(else_value == NULL)
    return NULL;

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

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

  if(is_control_type(type))
    return GEN_NOVALUE;

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

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

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

    return phi;
  }

  return GEN_NOTNEEDED;
}
Esempio n. 14
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;
}
Esempio n. 15
0
LLVMValueRef gen_if(compile_t* c, ast_t* ast)
{
  bool needed = is_result_needed(ast);
  ast_t* type = ast_type(ast);
  AST_GET_CHILDREN(ast, cond, left, right);

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

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

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

  LLVMValueRef c_value = gen_expr(c, cond);

  if(c_value == NULL)
    return NULL;

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

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

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

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

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

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

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

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

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

    if(l_value == NULL)
      return NULL;

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

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

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

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

    if(r_value == NULL)
      return NULL;

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

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

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

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

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

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

    return phi;
  }

  return GEN_NOTNEEDED;
}
Esempio n. 16
0
File: control.c Progetto: ozra/ponyc
bool expr_return(pass_opt_t* opt, ast_t* ast)
{
    typecheck_t* t = &opt->check;

    if(t->frame->method_body == NULL)
    {
        ast_error(ast, "return must occur in a method body");
        return false;
    }

    // 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_none(body_type))
        {
            ast_error(ast, "return in a constructor must return None");
            ok = false;
        }
        break;

    case TK_BE:
        if(!is_none(body_type))
        {
            ast_error(ast, "return in a behaviour must return None");
            ok = false;
        }
        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);

        if(!is_subtype(body_type, type) || !is_subtype(a_body_type, a_type))
        {
            ast_t* last = ast_childlast(body);
            ast_error(last, "returned value isn't the return type");
            ast_error(type, "function return type: %s", ast_print_type(type));
            ast_error(body_type, "returned value type: %s",
                      ast_print_type(body_type));
            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;
}
Esempio n. 17
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;
}
Esempio n. 18
0
File: control.c Progetto: ozra/ponyc
bool expr_try(pass_opt_t* opt, ast_t* ast)
{
    AST_GET_CHILDREN(ast, body, else_clause, then_clause);

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

    ast_t* 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(type, body);

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

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

        type = ast_from(ast, TK_TRY);
    }

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

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

    ast_settype(ast, type);

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

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

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

    literal_unify_control(ast, opt);

    // Push the symbol status from the then clause to our parent scope.
    ast_inheritstatus(ast_parent(ast), then_clause);
    return true;
}
Esempio n. 19
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;
}
Esempio n. 20
0
LLVMValueRef gen_try(compile_t* c, ast_t* ast)
{
  bool needed = is_result_needed(ast);
  AST_GET_CHILDREN(ast, body, else_clause, then_clause);

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

  reach_type_t* phi_type = NULL;

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

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

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

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

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

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

    if(body_value == NULL)
      return NULL;

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

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

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

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

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

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

  LLVMValueRef else_value = gen_expr(c, else_clause);

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

    if(else_value == NULL)
      return NULL;

    gen_expr(c, then_clause);

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

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

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

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

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

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

    return phi;
  }

  return GEN_NOTNEEDED;
}
Esempio n. 21
0
File: match.c Progetto: mgist/ponyc
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;
}
Esempio n. 22
0
File: match.c Progetto: mgist/ponyc
bool expr_match(pass_opt_t* opt, ast_t* ast)
{
  assert(ast_id(ast) == TK_MATCH);
  AST_GET_CHILDREN(ast, expr, cases, else_clause);

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

  if(is_typecheck_error(expr_type))
    return false;

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

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

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

  ast_t* type = NULL;
  size_t branch_count = 0;

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

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

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

    type = ast_from(ast, TK_MATCH);
  }

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

  // Push our symbol status to our parent scope.
  ast_inheritstatus(ast_parent(ast), ast);
  return true;
}
Esempio n. 23
0
File: match.c Progetto: mgist/ponyc
static bool is_valid_pattern(pass_opt_t* opt, ast_t* pattern)
{
  if(ast_id(pattern) == TK_NONE)
  {
    ast_settype(pattern, ast_from(pattern, TK_DONTCARE));
    return true;
  }

  ast_t* pattern_type = ast_type(pattern);

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

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

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

        return false;
      }

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

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

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

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

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

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

      ast_settype(pattern, pattern_type);
      return ok;
    }

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

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

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

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

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

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

        return false;
      }

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

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

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

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

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

      ast_t* param = ast_child(params);

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

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

      ast_free_unattached(fun);
      return ok;
    }
  }

  assert(0);
  return false;
}