static void reachable_method(reachable_method_stack_t** s, reachable_types_t* r, uint32_t* next_type_id, ast_t* type, const char* name, ast_t* typeargs) { switch(ast_id(type)) { case TK_NOMINAL: { reachable_type_t* t = add_type(s, r, next_type_id, type); add_method(s, t, name, typeargs); break; } case TK_UNIONTYPE: case TK_ISECTTYPE: { ast_t* child = ast_child(type); while(child != NULL) { ast_t* find = lookup_try(NULL, NULL, child, name); if(find != NULL) reachable_method(s, r, next_type_id, child, name, typeargs); child = ast_sibling(child); } break; } default: assert(0); } }
static void add_rmethod_to_subtypes(reach_t* r, reach_type_t* t, reach_method_name_t* n, reach_method_t* m, pass_opt_t* opt) { switch(ast_id(t->ast)) { case TK_NOMINAL: { ast_t* def = (ast_t*)ast_data(t->ast); switch(ast_id(def)) { case TK_INTERFACE: case TK_TRAIT: { // Add to subtypes if we're an interface or trait. size_t i = HASHMAP_BEGIN; reach_type_t* t2; while((t2 = reach_type_cache_next(&t->subtypes, &i)) != NULL) add_rmethod_to_subtype(r, t2, n, m, opt); break; } default: {} } return; } case TK_UNIONTYPE: case TK_ISECTTYPE: { ast_t* child = ast_child(t->ast); while(child != NULL) { ast_t* find = lookup_try(NULL, NULL, child, n->name); if(find != NULL) { reach_type_t* t2 = add_type(r, child, opt); add_rmethod_to_subtype(r, t2, n, m, opt); ast_free_unattached(find); } child = ast_sibling(child); } return; } default: {} } assert(0); }
static void add_special(reachable_method_stack_t** s, reachable_type_t* t, ast_t* type, const char* special) { special = stringtab(special); ast_t* find = lookup_try(NULL, NULL, type, special); if(find != NULL) { add_method(s, t, special, NULL); ast_free_unattached(find); } }
static bool is_constructed_from(pass_opt_t* opt, ast_t* ast, ast_t* type) { ast_t* parent = ast_parent(ast); if(ast_id(parent) != TK_DOT) return false; AST_GET_CHILDREN(parent, left, right); ast_t* find = lookup_try(opt, parent, type, ast_name(right)); if(find == NULL) return false; bool ok = ast_id(find) == TK_NEW; ast_free_unattached(find); return ok; }
static ast_t* get_fun(gentype_t* g, const char* name, ast_t* typeargs) { ast_t* this_type = set_cap_and_ephemeral(g->ast, TK_REF, TK_NONE); ast_t* fun = lookup_try(NULL, NULL, this_type, name); ast_free_unattached(this_type); assert(fun != NULL); if(typeargs != NULL) { ast_t* typeparams = ast_childidx(fun, 2); ast_t* r_fun = reify(typeparams, fun, typeparams, typeargs); ast_free_unattached(fun); fun = r_fun; assert(fun != NULL); } return fun; }
static void add_special(reach_t* r, reach_type_t* t, ast_t* type, const char* special, pass_opt_t* opt) { special = stringtab(special); ast_t* find = lookup_try(NULL, NULL, type, special); if(find != NULL) { switch(ast_id(find)) { case TK_NEW: case TK_FUN: case TK_BE: { reachable_method(r, t->ast, special, NULL, opt); ast_free_unattached(find); break; } default: {} } } }
bool expr_this(pass_opt_t* opt, ast_t* ast) { typecheck_t* t = &opt->check; if(t->frame->def_arg != NULL) { ast_error(opt->check.errors, ast, "can't reference 'this' in a default argument"); return false; } sym_status_t status; ast_get(ast, stringtab("this"), &status); if(status == SYM_CONSUMED) { ast_error(opt->check.errors, ast, "can't use a consumed 'this' in an expression"); return false; } assert(status == SYM_NONE); token_id cap = cap_for_this(t); if(!cap_sendable(cap) && (t->frame->recover != NULL)) { ast_t* parent = ast_parent(ast); if(ast_id(parent) != TK_DOT) cap = TK_TAG; } bool make_arrow = false; if(cap == TK_BOX) { cap = TK_REF; make_arrow = true; } ast_t* type = type_for_this(opt, ast, cap, TK_NONE, false); if(make_arrow) { BUILD(arrow, ast, NODE(TK_ARROW, NODE(TK_THISTYPE) TREE(type))); type = arrow; } // Get the nominal type, which may be the right side of an arrow type. ast_t* nominal; bool arrow; if(ast_id(type) == TK_NOMINAL) { nominal = type; arrow = false; } else { nominal = ast_childidx(type, 1); arrow = true; } ast_t* typeargs = ast_childidx(nominal, 2); ast_t* typearg = ast_child(typeargs); while(typearg != NULL) { if(!expr_nominal(opt, &typearg)) { ast_error(opt->check.errors, ast, "couldn't create a type for 'this'"); ast_free(type); return false; } typearg = ast_sibling(typearg); } if(!expr_nominal(opt, &nominal)) { ast_error(opt->check.errors, ast, "couldn't create a type for 'this'"); ast_free(type); return false; } // Unless this is a field lookup, treat an incomplete `this` as a tag. ast_t* parent = ast_parent(ast); bool incomplete_ok = false; if((ast_id(parent) == TK_DOT) && (ast_child(parent) == ast)) { ast_t* right = ast_sibling(ast); assert(ast_id(right) == TK_ID); ast_t* find = lookup_try(opt, ast, nominal, ast_name(right)); if(find != NULL) { switch(ast_id(find)) { case TK_FVAR: case TK_FLET: case TK_EMBED: incomplete_ok = true; break; default: {} } } } if(!incomplete_ok && is_this_incomplete(t, ast)) { ast_t* tag_type = set_cap_and_ephemeral(nominal, TK_TAG, TK_NONE); ast_replace(&nominal, tag_type); } if(arrow) type = ast_parent(nominal); else type = nominal; ast_settype(ast, type); return true; }