void fun_defaults(ast_t* ast) { assert(ast != NULL); AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body, docstring); // If the receiver cap is not specified, set it to box. if(ast_id(cap) == TK_NONE) ast_setid(cap, TK_BOX); // If the return value is not specified, set it to None. if(ast_id(result) == TK_NONE) { ast_t* type = type_sugar(ast, NULL, "None"); ast_replace(&result, type); } // If the return type is None, add a None at the end of the body, unless it // already ends with an error or return statement if(is_none(result) && (ast_id(body) != TK_NONE)) { ast_t* last_cmd = ast_childlast(body); if(ast_id(last_cmd) != TK_ERROR && ast_id(last_cmd) != TK_RETURN) { BUILD_NO_DEBUG(ref, body, NODE(TK_REFERENCE, ID("None"))); ast_append(body, ref); } } }
ast_t* type_for_this(typecheck_t* t, ast_t* ast, token_id cap, token_id ephemeral) { bool make_arrow = false; if(cap == TK_BOX) { cap = TK_REF; make_arrow = true; } AST_GET_CHILDREN(t->frame->type, id, typeparams); BUILD(typeargs, ast, NODE(TK_NONE)); BUILD(type, ast, NODE(TK_NOMINAL, NODE(TK_NONE) TREE(id) TREE(typeargs) NODE(cap) NODE(ephemeral))); if(ast_id(typeparams) == TK_TYPEPARAMS) { ast_setid(typeargs, TK_TYPEARGS); ast_t* typeparam = ast_child(typeparams); while(typeparam != NULL) { ast_t* typeparam_id = ast_child(typeparam); ast_t* typearg = type_sugar(ast, NULL, ast_name(typeparam_id)); ast_append(typeargs, typearg); typeparam = ast_sibling(typeparam); } } if(make_arrow) { BUILD(arrow, ast, NODE(TK_ARROW, NODE(TK_THISTYPE) TREE(type))); return arrow; } return type; }
static bool package_access(pass_opt_t* opt, ast_t** astp) { ast_t* ast = *astp; // Left is a packageref, right is an id. ast_t* left = ast_child(ast); ast_t* right = ast_sibling(left); ast_t* type = ast_type(left); if(is_typecheck_error(type)) return false; assert(ast_id(left) == TK_PACKAGEREF); assert(ast_id(right) == TK_ID); // Must be a type in a package. const char* package_name = ast_name(ast_child(left)); ast_t* package = ast_get(left, package_name, NULL); if(package == NULL) { ast_error(right, "can't access package '%s'", package_name); return false; } assert(ast_id(package) == TK_PACKAGE); const char* type_name = ast_name(right); type = ast_get(package, type_name, NULL); if(type == NULL) { ast_error(right, "can't find type '%s' in package '%s'", type_name, package_name); return false; } ast_settype(ast, type_sugar(ast, package_name, type_name)); ast_setid(ast, TK_TYPEREF); return expr_typeref(opt, astp); }
bool expr_reference(pass_opt_t* opt, ast_t** astp) { typecheck_t* t = &opt->check; ast_t* ast = *astp; // Everything we reference must be in scope. const char* name = ast_name(ast_child(ast)); sym_status_t status; ast_t* def = ast_get(ast, name, &status); if(def == NULL) { const char* alt_name = suggest_alt_name(ast, name); if(alt_name == NULL) ast_error(ast, "can't find declaration of '%s'", name); else ast_error(ast, "can't find declaration of '%s', did you mean '%s'?", name, alt_name); return false; } switch(ast_id(def)) { case TK_PACKAGE: { // Only allowed if in a TK_DOT with a type. if(ast_id(ast_parent(ast)) != TK_DOT) { ast_error(ast, "a package can only appear as a prefix to a type"); return false; } ast_setid(ast, TK_PACKAGEREF); return true; } case TK_INTERFACE: case TK_TRAIT: case TK_TYPE: case TK_TYPEPARAM: case TK_PRIMITIVE: case TK_STRUCT: case TK_CLASS: case TK_ACTOR: { // It's a type name. This may not be a valid type, since it may need // type arguments. ast_t* id = ast_child(def); const char* name = ast_name(id); ast_t* type = type_sugar(ast, NULL, name); ast_settype(ast, type); ast_setid(ast, TK_TYPEREF); return expr_typeref(opt, astp); } case TK_FVAR: case TK_FLET: case TK_EMBED: { // Transform to "this.f". if(!def_before_use(def, ast, name)) return false; ast_t* dot = ast_from(ast, TK_DOT); ast_add(dot, ast_child(ast)); ast_t* self = ast_from(ast, TK_THIS); ast_add(dot, self); ast_replace(astp, dot); if(!expr_this(opt, self)) return false; return expr_dot(opt, astp); } case TK_PARAM: { if(t->frame->def_arg != NULL) { ast_error(ast, "can't reference a parameter in a default argument"); return false; } if(!def_before_use(def, ast, name)) return false; ast_t* type = ast_type(def); if(is_typecheck_error(type)) return false; if(!valid_reference(opt, ast, type, status)) return false; if(!sendable(type) && (t->frame->recover != NULL)) { ast_error(ast, "can't access a non-sendable parameter from inside a recover " "expression"); return false; } // Get the type of the parameter and attach it to our reference. // Automatically consume a parameter if the function is done. ast_t* r_type = type; if(is_method_return(t, ast)) r_type = consume_type(type, TK_NONE); ast_settype(ast, r_type); ast_setid(ast, TK_PARAMREF); return true; } case TK_NEW: case TK_BE: case TK_FUN: { // Transform to "this.f". ast_t* dot = ast_from(ast, TK_DOT); ast_add(dot, ast_child(ast)); ast_t* self = ast_from(ast, TK_THIS); ast_add(dot, self); ast_replace(astp, dot); if(!expr_this(opt, self)) return false; return expr_dot(opt, astp); } case TK_ID: { if(!def_before_use(def, ast, name)) return false; ast_t* type = ast_type(def); if(type != NULL && ast_id(type) == TK_INFERTYPE) { ast_error(ast, "cannot infer type of %s\n", ast_nice_name(def)); ast_settype(def, ast_from(def, TK_ERRORTYPE)); ast_settype(ast, ast_from(ast, TK_ERRORTYPE)); return false; } if(is_typecheck_error(type)) return false; if(!valid_reference(opt, ast, type, status)) return false; ast_t* var = ast_parent(def); switch(ast_id(var)) { case TK_VAR: ast_setid(ast, TK_VARREF); break; case TK_LET: case TK_MATCH_CAPTURE: ast_setid(ast, TK_LETREF); break; default: assert(0); return false; } if(!sendable(type)) { if(t->frame->recover != NULL) { ast_t* def_recover = ast_nearest(def, TK_RECOVER); if(t->frame->recover != def_recover) { ast_error(ast, "can't access a non-sendable local defined outside " "of a recover expression from within that recover expression"); return false; } } } // Get the type of the local and attach it to our reference. // Automatically consume a local if the function is done. ast_t* r_type = type; if(is_method_return(t, ast)) r_type = consume_type(type, TK_NONE); ast_settype(ast, r_type); return true; } default: {} } assert(0); return false; }