static bool method_chain(pass_opt_t* opt, ast_t* ast) { if(!method_application(opt, ast, false)) return false; // We check the receiver cap now instead of in method_application because // we need to know whether the receiver was recovered. ast_t* lhs = ast_childidx(ast, 2); ast_t* r_type = method_receiver_type(lhs); if(ast_id(lhs) == TK_FUNCHAIN) { bool recovered; if(!check_receiver_cap(opt, ast, &recovered)) return false; if(!check_nonsendable_recover(opt, ast)) return false; ast_t* f_type = ast_type(lhs); token_id f_cap = ast_id(ast_child(f_type)); ast_t* c_type = chain_type(r_type, f_cap, recovered); ast_settype(ast, c_type); } else { ast_settype(ast, r_type); } return true; }
static bool method_application(pass_opt_t* opt, ast_t* ast, bool partial) { AST_GET_CHILDREN(ast, positional, namedargs, question, lhs); if(!method_check_type_params(opt, &lhs)) return false; ast_t* type = ast_type(lhs); if(is_typecheck_error(type)) return false; AST_GET_CHILDREN(type, cap, typeparams, params, result); if(!extend_positional_args(opt, params, positional)) return false; if(!apply_named_args(opt, params, positional, namedargs)) return false; if(!check_arg_types(opt, params, positional, partial)) return false; switch(ast_id(lhs)) { case TK_FUNREF: case TK_FUNAPP: if(ast_id(ast_child(type)) != TK_AT) { if(!check_receiver_cap(opt, ast, NULL)) return false; if(!check_nonsendable_recover(opt, ast)) return false; } else { ast_t* receiver = ast_child(lhs); // Dig through function qualification. if((ast_id(receiver) == TK_FUNREF) || (ast_id(receiver) == TK_FUNAPP) || (ast_id(receiver) == TK_FUNCHAIN)) receiver = ast_child(receiver); ast_t* recv_type = ast_type(receiver); if(!is_known(recv_type) && (ast_id(receiver) == TK_TYPEREF)) { ast_error(opt->check.errors, lhs, "a bare method cannot be called on " "an abstract type reference"); return false; } } break; default: {} } return true; }
static bool method_application(pass_opt_t* opt, ast_t* ast, bool partial) { AST_GET_CHILDREN(ast, positional, namedargs, lhs); if(!check_type_params(opt, &lhs)) return false; ast_t* type = ast_type(lhs); if(is_typecheck_error(type)) return false; AST_GET_CHILDREN(type, cap, typeparams, params, result); if(!extend_positional_args(opt, params, positional)) return false; if(!apply_named_args(opt, params, positional, namedargs)) return false; if(!check_arg_types(opt, params, positional, partial)) return false; switch(ast_id(lhs)) { case TK_FUNREF: case TK_FUNAPP: if(!check_receiver_cap(opt, ast, NULL)) return false; if(!check_nonsendable_recover(opt, ast)) return false; break; default: {} } return true; }
static bool method_application(pass_opt_t* opt, ast_t* ast, bool partial) { // TODO: use args to decide unbound type parameters AST_GET_CHILDREN(ast, positional, namedargs, lhs); if(!check_type_params(&lhs)) return false; ast_t* type = ast_type(lhs); if(is_typecheck_error(type)) return false; AST_GET_CHILDREN(type, cap, typeparams, params, result); if(!extend_positional_args(params, positional)) return false; if(!apply_named_args(params, positional, namedargs)) return false; bool incomplete = is_this_incomplete(&opt->check, ast); if(!check_arg_types(opt, params, positional, incomplete, partial)) return false; switch(ast_id(lhs)) { case TK_FUNREF: case TK_FUNAPP: if(!check_receiver_cap(ast, incomplete)) return false; break; default: {} } return true; }
static bool method_chain(pass_opt_t* opt, ast_t* ast) { if(!method_application(opt, ast, false)) return false; AST_GET_CHILDREN(ast, positional, namedargs, question, lhs); ast_t* type = ast_type(lhs); if(ast_id(ast_child(type)) == TK_AT) { ast_error(opt->check.errors, ast, "a bare method cannot be chained"); return false; } // We check the receiver cap now instead of in method_application because // we need to know whether the receiver was recovered. ast_t* r_type = method_receiver_type(lhs); if(ast_id(lhs) == TK_FUNCHAIN) { bool recovered; if(!check_receiver_cap(opt, ast, &recovered)) return false; if(!check_nonsendable_recover(opt, ast)) return false; ast_t* f_type = ast_type(lhs); token_id f_cap = ast_id(ast_child(f_type)); ast_t* c_type = chain_type(r_type, f_cap, recovered); ast_settype(ast, c_type); } else { ast_settype(ast, r_type); } return true; }