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; }
bool expr_recover(pass_opt_t* opt, 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) { ast_error(opt->check.errors, ast, "can't recover to this capability"); ast_error_continue(opt->check.errors, expr, "expression type is %s", ast_print_type(type)); return false; } ast_settype(ast, r_type); // Push our symbol status to our parent scope. ast_inheritstatus(ast_parent(ast), expr); return true; }
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_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; }
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; }
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; }