static bool check_receiver_cap(pass_opt_t* opt, ast_t* ast, bool incomplete) { 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); // Check receiver cap. ast_t* receiver = ast_child(lhs); // Dig through function qualification. if(ast_id(receiver) == TK_FUNREF || ast_id(receiver) == TK_FUNAPP) receiver = ast_child(receiver); // Receiver type, alias of receiver type, and target type. ast_t* r_type = ast_type(receiver); if(is_typecheck_error(r_type)) return false; ast_t* t_type = set_cap_and_ephemeral(r_type, ast_id(cap), TK_NONE); ast_t* a_type; // If we can recover the receiver, we don't alias it here. bool can_recover = auto_recover_call(ast, r_type, positional, result); bool cap_recover = false; switch(ast_id(cap)) { case TK_ISO: case TK_TRN: case TK_VAL: case TK_TAG: break; case TK_REF: case TK_BOX: cap_recover = true; break; default: assert(0); } if(can_recover && cap_recover) a_type = r_type; else a_type = alias(r_type); if(incomplete && (ast_id(receiver) == TK_THIS)) { // If 'this' is incomplete and the arg is 'this', change the type to tag. ast_t* tag_type = set_cap_and_ephemeral(a_type, TK_TAG, TK_NONE); if(a_type != r_type) ast_free_unattached(a_type); a_type = tag_type; } else { incomplete = false; } errorframe_t info = NULL; bool ok = is_subtype(a_type, t_type, &info, opt); if(!ok) { errorframe_t frame = NULL; ast_error_frame(&frame, ast, "receiver type is not a subtype of target type"); ast_error_frame(&frame, receiver, "receiver type: %s", ast_print_type(a_type)); ast_error_frame(&frame, cap, "target type: %s", ast_print_type(t_type)); if(!can_recover && cap_recover && is_subtype(r_type, t_type, NULL, opt)) { ast_error_frame(&frame, ast, "this would be possible if the arguments and return value " "were all sendable"); } if(incomplete && is_subtype(r_type, t_type, NULL, opt)) { ast_error_frame(&frame, ast, "this would be possible if all the fields of 'this' were assigned to " "at this point"); } errorframe_append(&frame, &info); errorframe_report(&frame, opt->check.errors); } if(a_type != r_type) ast_free_unattached(a_type); ast_free_unattached(r_type); ast_free_unattached(t_type); return ok; }
static bool check_receiver_cap(pass_opt_t* opt, ast_t* ast, bool* recovered) { AST_GET_CHILDREN(ast, positional, namedargs, question, lhs); ast_t* type = ast_type(lhs); if(is_typecheck_error(type)) return false; AST_GET_CHILDREN(type, cap, typeparams, params, result); // Receiver type, alias of receiver type, and target type. ast_t* r_type = method_receiver_type(lhs); if(is_typecheck_error(r_type)) return false; ast_t* t_type = set_cap_and_ephemeral(r_type, ast_id(cap), TK_NONE); ast_t* a_type; // If we can recover the receiver, we don't alias it here. bool can_recover = auto_recover_call(lhs, r_type, positional, result); bool cap_recover = false; switch(ast_id(cap)) { case TK_ISO: case TK_TRN: case TK_VAL: case TK_TAG: break; case TK_REF: case TK_BOX: cap_recover = true; break; default: pony_assert(0); } if(can_recover && cap_recover) { a_type = r_type; if(recovered != NULL) *recovered = true; } else { a_type = alias(r_type); if(recovered != NULL) *recovered = false; } errorframe_t info = NULL; bool ok = is_subtype(a_type, t_type, &info, opt); if(!ok) { errorframe_t frame = NULL; ast_error_frame(&frame, ast, "receiver type is not a subtype of target type"); ast_error_frame(&frame, ast_child(lhs), "receiver type: %s", ast_print_type(a_type)); ast_error_frame(&frame, cap, "target type: %s", ast_print_type(t_type)); errorframe_append(&frame, &info); if(ast_checkflag(ast_type(method_receiver(lhs)), AST_FLAG_INCOMPLETE)) ast_error_frame(&frame, method_receiver(lhs), "this might be possible if all fields were already defined"); if(!can_recover && cap_recover && is_subtype(r_type, t_type, NULL, opt)) { ast_error_frame(&frame, ast, "this would be possible if the arguments and return value " "were all sendable"); } errorframe_report(&frame, opt->check.errors); } if(a_type != r_type) ast_free_unattached(a_type); ast_free_unattached(r_type); ast_free_unattached(t_type); return ok; }