static bool method_call(pass_opt_t* opt, ast_t* ast) { if(!method_application(opt, ast, false)) return false; AST_GET_CHILDREN(ast, positional, namedargs, lhs); ast_t* type = ast_type(lhs); if(is_typecheck_error(type)) return false; AST_GET_CHILDREN(type, cap, typeparams, params, result); ast_settype(ast, result); ast_inheritflags(ast); switch(ast_id(lhs)) { case TK_NEWBEREF: case TK_BEREF: ast_setsend(ast); return true; case TK_NEWREF: case TK_FUNREF: ast_setmightsend(ast); return true; default: {} } assert(0); return false; }
static int check_body_send(ast_t* ast, bool in_final) { if(ast_checkflag(ast, AST_FLAG_RECURSE_1)) return FINAL_RECURSE; if(ast_cansend(ast)) return FINAL_CAN_SEND; if(!ast_mightsend(ast)) return FINAL_NO_SEND; ast_setflag(ast, AST_FLAG_RECURSE_1); int r = check_expr_send(ast, in_final); if(r == FINAL_NO_SEND) { // Mark the body as no send. ast_clearmightsend(ast); } else if((r & FINAL_CAN_SEND) != 0) { // Mark the body as can send. ast_setsend(ast); } ast_clearflag(ast, AST_FLAG_RECURSE_1); return r; }
bool verify_behaviour_call(pass_opt_t* opt, ast_t* ast) { (void)opt; pony_assert((ast_id(ast) == TK_BEREF) || (ast_id(ast) == TK_BECHAIN) || (ast_id(ast) == TK_NEWBEREF)); ast_inheritflags(ast); ast_setsend(ast); return true; }
static int check_call_send(ast_t* ast, bool in_final) { AST_GET_CHILDREN(ast, positional, named, question, lhs); AST_GET_CHILDREN(lhs, receiver, method); switch(ast_id(receiver)) { case TK_NEWREF: case TK_FUNREF: case TK_FUNCHAIN: // Qualified. Get the real receiver. receiver = ast_child(receiver); method = ast_sibling(receiver); break; default: {} } ast_t* type = ast_type(receiver); // If we don't know the final type, we can't be certain of what all // implementations of the method do. Leave it as might send. if(!is_known(type)) return FINAL_CAN_SEND; ast_t* def = receiver_def(type); pony_assert(def != NULL); const char* method_name = ast_name(method); ast_t* fun = ast_get(def, method_name, NULL); pony_assert(fun != NULL); AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, can_error, body); int r = check_body_send(body, false); if(r == FINAL_NO_SEND) { // Mark the call as no send. ast_clearmightsend(ast); } else if(in_final && (r == FINAL_RECURSE)) { // If we're in the finaliser, which can't recurse, we treat a recurse as // a no send. ast_clearmightsend(ast); } else if((r & FINAL_CAN_SEND) != 0) { // Mark the call as can send. ast_setsend(ast); } return r; }
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; }