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; }
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; }
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; }
bool expr_seq(pass_opt_t* opt, ast_t* ast) { bool ok = true; // Any expression other than the last that is still literal is an error for(ast_t* p = ast_child(ast); ast_sibling(p) != NULL; p = ast_sibling(p)) { ast_t* p_type = ast_type(p); if(is_typecheck_error(p_type)) { ok = false; } else if(is_type_literal(p_type)) { ast_error(p, "Cannot infer type of unused literal"); ok = false; } } // We might already have a type due to a return expression. ast_t* type = ast_type(ast); ast_t* last = ast_childlast(ast); if((type != NULL) && !coerce_literals(&last, type, opt)) return false; // Type is unioned with the type of the last child. type = control_type_add_branch(type, last); ast_settype(ast, type); ast_inheritflags(ast); if(!ast_has_scope(ast)) return ok; ast_t* parent = ast_parent(ast); switch(ast_id(parent)) { case TK_TRY: case TK_TRY_NO_CHECK: { // Propagate consumes forward in a try expression. AST_GET_CHILDREN(parent, body, else_clause, then_clause); if(body == ast) { // Push our consumes, but not defines, to the else clause. ast_inheritbranch(else_clause, body); ast_consolidate_branches(else_clause, 2); } else if(else_clause == ast) { // Push our consumes, but not defines, to the then clause. This // includes the consumes from the body. ast_inheritbranch(then_clause, else_clause); ast_consolidate_branches(then_clause, 2); } } default: {} } return ok; }
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; }