ast_t* deferred_reify_method_def(deferred_reification_t* deferred, ast_t* ast, pass_opt_t* opt) { switch(ast_id(ast)) { case TK_FUN: case TK_BE: case TK_NEW: break; default: pony_assert(false); } // Do not duplicate the body and docstring. bool dup_child[9] = {true, true, true, true, true, true, false, false, true}; ast_t* r_ast = ast_dup_partial(ast, dup_child, true, true, true); // Must replace `this` before typeparam reification. if(deferred->thistype != NULL) r_ast = viewpoint_replacethis(r_ast, deferred->thistype, false); if(deferred->type_typeparams != NULL) r_ast = reify(r_ast, deferred->type_typeparams, deferred->type_typeargs, opt, false); if(deferred->method_typeparams != NULL) r_ast = reify(r_ast, deferred->method_typeparams, deferred->method_typeargs, opt, false); return r_ast; }
template <typename... A> bool equals(auto left,auto right,A... arguments) { auto left_value=reify(left); auto right_value=reify(right); //equals if(!left_value.equals(right_value)) return false; //rest return equals(arguments...); }
static bool is_nominal_sub_interface(ast_t* sub, ast_t* super) { ast_t* sub_def = (ast_t*)ast_data(sub); ast_t* super_def = (ast_t*)ast_data(super); ast_t* sub_typeargs = ast_childidx(sub, 2); ast_t* super_typeargs = ast_childidx(super, 2); ast_t* sub_typeparams = ast_childidx(sub_def, 1); ast_t* super_typeparams = ast_childidx(super_def, 1); ast_t* super_members = ast_childidx(super_def, 4); ast_t* super_member = ast_child(super_members); while(super_member != NULL) { ast_t* super_member_id = ast_childidx(super_member, 1); ast_t* sub_member = ast_get(sub_def, ast_name(super_member_id), NULL); if(sub_member == NULL) return false; ast_t* r_sub_member = reify(sub_typeargs, sub_member, sub_typeparams, sub_typeargs); if(r_sub_member== NULL) return false; ast_t* r_super_member = reify(super_typeargs, super_member, super_typeparams, super_typeargs); if(r_super_member == NULL) { ast_free_unattached(r_sub_member); return false; } bool ok = is_fun_sub_fun(r_sub_member, r_super_member, sub, super); ast_free_unattached(r_sub_member); ast_free_unattached(r_super_member); if(!ok) return false; super_member = ast_sibling(super_member); } return true; }
static bool names_typealias(pass_opt_t* opt, ast_t** astp, ast_t* def) { ast_t* ast = *astp; AST_GET_CHILDREN(ast, pkg, id, typeargs, cap, eph); // Make sure the alias is resolved, AST_GET_CHILDREN(def, alias_id, typeparams, def_cap, provides); ast_t* alias = ast_child(provides); if(!names_resolvealias(opt, def, &alias)) return false; // Reify the alias. ast_t* r_alias = reify(typeparams, alias, typeparams, typeargs); if(r_alias == NULL) return false; // Apply our cap and ephemeral to the result. if(!names_applycap(r_alias, cap, eph)) { ast_free_unattached(r_alias); return false; } // Maintain the position info of the original reference to aid error // reporting. ast_setpos(r_alias, ast_line(ast), ast_pos(ast)); // Replace this with the alias. ast_replace(astp, r_alias); return true; }
ast_t* reify_method_def(ast_t* ast, ast_t* typeparams, ast_t* typeargs, pass_opt_t* opt) { (void)opt; switch(ast_id(ast)) { case TK_FUN: case TK_BE: case TK_NEW: break; default: pony_assert(false); } // Remove the body AST to avoid duplicating it. ast_t* body = ast_childidx(ast, 6); ast_t* temp_body = ast_blank(TK_NONE); ast_swap(body, temp_body); ast_t* r_ast = reify(ast, typeparams, typeargs, opt, true); ast_swap(temp_body, body); ast_free_unattached(temp_body); return r_ast; }
void deferred_reify_add_method_typeparams(deferred_reification_t* deferred, ast_t* typeparams, ast_t* typeargs, pass_opt_t* opt) { pony_assert((deferred->method_typeparams == NULL) && (deferred->method_typeargs == NULL)); pony_assert(((typeparams != NULL) && (typeargs != NULL)) || ((typeparams == NULL) && (typeargs == NULL))); if(typeparams == NULL) return; ast_t* r_typeparams = ast_dup(typeparams); deferred->method_typeargs = ast_dup(typeargs); // Must replace `this` before typeparam reification. if(deferred->thistype != NULL) r_typeparams = viewpoint_replacethis(r_typeparams, deferred->thistype, false); if(deferred->type_typeparams != NULL) r_typeparams = reify(r_typeparams, deferred->type_typeparams, deferred->type_typeargs, opt, false); deferred->method_typeparams = r_typeparams; }
static void add_rmethod(reachable_method_stack_t** s, reachable_type_t* t, reachable_method_name_t* n, ast_t* typeargs) { const char* name = genname_fun(NULL, n->name, typeargs); reachable_method_t* m = reach_method(n, name); if(m == NULL) { m = POOL_ALLOC(reachable_method_t); m->name = name; m->typeargs = ast_dup(typeargs); m->vtable_index = (uint32_t)-1; ast_t* fun = lookup(NULL, NULL, t->type, n->name); if(typeargs != NULL) { // Reify the method with its typeargs, if it has any. AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, can_error, body); ast_t* r_fun = reify(fun, typeparams, typeargs); ast_free_unattached(fun); fun = r_fun; } m->r_fun = ast_dup(fun); ast_free_unattached(fun); reachable_methods_put(&n->r_methods, m); // Put on a stack of reachable methods to trace. *s = reachable_method_stack_push(*s, m); } }
// Reify the method with the type parameters from trait definition // and type arguments from trait reference. // Also handles modifying return types from behaviours, etc. // Returns the reified type, which must be freed later, or NULL on error. static ast_t* reify_provides_type(ast_t* method, ast_t* trait_ref, pass_opt_t* opt) { assert(method != NULL); assert(trait_ref != NULL); // Apply the type args (if any) from the trait reference to the type // parameters from the trait definition. ast_t* trait_def = (ast_t*)ast_data(trait_ref); assert(trait_def != NULL); ast_t* type_args = ast_childidx(trait_ref, 2); ast_t* type_params = ast_childidx(trait_def, 1); if(!reify_defaults(type_params, type_args, true, opt)) return NULL; ast_t* reified = reify(method, type_params, type_args, opt); if(reified == NULL) return NULL; AST_GET_CHILDREN(reified, cap, id, typeparams, params, result, can_error, body, doc); return reified; }
template <typename... A> int compare(auto left,auto right,A... arguments) { auto left_value=reify(left); auto right_value=reify(right); //compare int result=left_value.compare(right_value); if(result!=0) return result; //rest return compare(arguments...); }
static bool check_type_params(ast_t** astp) { ast_t* lhs = *astp; ast_t* type = ast_type(lhs); if(is_typecheck_error(type)) return false; ast_t* typeparams = ast_childidx(type, 1); assert(ast_id(type) == TK_FUNTYPE); if(ast_id(typeparams) == TK_NONE) return true; BUILD(typeargs, typeparams, NODE(TK_TYPEARGS)); if(!check_constraints(typeparams, typeargs, true)) { ast_free_unattached(typeargs); return false; } type = reify(type, typeparams, typeargs); typeparams = ast_childidx(type, 1); ast_replace(&typeparams, ast_from(typeparams, TK_NONE)); REPLACE(astp, NODE(ast_id(lhs), TREE(lhs) TREE(typeargs))); ast_settype(*astp, type); return true; }
ast_t* deferred_reify(deferred_reification_t* deferred, ast_t* ast, pass_opt_t* opt) { ast_t* r_ast = ast_dup(ast); // Must replace `this` before typeparam reification. if(deferred->thistype != NULL) r_ast = viewpoint_replacethis(r_ast, deferred->thistype, false); if(deferred->type_typeparams != NULL) r_ast = reify(r_ast, deferred->type_typeparams, deferred->type_typeargs, opt, false); if(deferred->method_typeparams != NULL) r_ast = reify(r_ast, deferred->method_typeparams, deferred->method_typeargs, opt, false); return r_ast; }
// Process the method provided to the given entity. // Stage 2. static bool provided_methods(ast_t* entity) { assert(entity != NULL); ast_t* provides = ast_childidx(entity, 3); ast_t* entity_members = ast_childidx(entity, 4); ast_t* last_member = ast_childlast(entity_members); bool r = true; // Run through our provides list for(ast_t* p = ast_child(provides); p != NULL; p = ast_sibling(p)) { ast_t* trait_def = (ast_t*)ast_data(p); assert(trait_def != NULL); ast_t* type_args = ast_childidx(p, 2); ast_t* type_params = ast_childidx(trait_def, 1); ast_t* members = ast_childidx(trait_def, 4); // Run through the methods of each provided type for(ast_t* m = ast_child(members); m != NULL; m = ast_sibling(m)) { // Check behaviour compatability if(ast_id(m) == TK_BE) { if(ast_id(entity) == TK_PRIMITIVE || ast_id(entity) == TK_CLASS) { ast_error(entity, "%s can't provide traits that have behaviours", (ast_id(entity) == TK_CLASS) ? "classes" : "primitives"); r = false; continue; } } if(is_method(m)) { // We have a provided method // Reify the method with the type parameters from trait definition and type // arguments from trait reference ast_t* reified = reify(type_args, m, type_params, type_args); if(reified == NULL) // Reification error, already reported return false; if(!provided_method(entity, reified, m, &last_member)) r = false; } } } return r; }
static reach_method_t* add_rmethod(reach_t* r, reach_type_t* t, reach_method_name_t* n, token_id cap, ast_t* typeargs, pass_opt_t* opt) { const char* name = genname_fun(cap, n->name, typeargs); reach_method_t* m = reach_rmethod(n, name); if(m != NULL) return m; m = POOL_ALLOC(reach_method_t); memset(m, 0, sizeof(reach_method_t)); m->name = name; m->cap = cap; m->typeargs = ast_dup(typeargs); m->vtable_index = (uint32_t)-1; ast_t* r_ast = set_cap_and_ephemeral(t->ast, cap, TK_NONE); ast_t* fun = lookup(NULL, NULL, r_ast, n->name); ast_free_unattached(r_ast); if(typeargs != NULL) { // Reify the method with its typeargs, if it has any. AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, can_error, body); fun = reify(fun, typeparams, typeargs, opt, false); } m->r_fun = fun; set_method_types(r, m, opt); m->mangled_name = make_mangled_name(m); m->full_name = make_full_name(t, m); // Add to both tables. reach_methods_put(&n->r_methods, m); reach_mangled_put(&n->r_mangled, m); // Put on a stack of reachable methods to trace. r->stack = reach_method_stack_push(r->stack, m); // Add the method to any subtypes. add_rmethod_to_subtypes(r, t, n, m, opt); return m; }
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(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 bool nominal_provides_trait(ast_t* type, ast_t* trait, errorframe_t* errors) { // Get our typeparams and typeargs. ast_t* def = (ast_t*)ast_data(type); AST_GET_CHILDREN(def, id, typeparams, defcap, traits); ast_t* typeargs = ast_childidx(type, 2); // Get cap and eph of the trait. AST_GET_CHILDREN(trait, t_pkg, t_name, t_typeparams, cap, eph); token_id tcap = ast_id(cap); token_id teph = ast_id(eph); // Check traits, depth first. ast_t* child = ast_child(traits); while(child != NULL) { // Reify the child with our typeargs. ast_t* r_child = reify(child, typeparams, typeargs); assert(r_child != NULL); // Use the cap and ephemerality of the trait. ast_t* rr_child = set_cap_and_ephemeral(r_child, tcap, teph); bool is_sub = is_subtype(rr_child, trait, NULL); ast_free_unattached(rr_child); if(r_child != child) ast_free_unattached(r_child); if(is_sub) return true; child = ast_sibling(child); } if(errors != NULL) { ast_error_frame(errors, type, "%s does not implement trait %s", ast_print_type(type), ast_print_type(trait)); } return false; }
ast_t* reify_method_def(ast_t* ast, ast_t* typeparams, ast_t* typeargs, pass_opt_t* opt) { switch(ast_id(ast)) { case TK_FUN: case TK_BE: case TK_NEW: break; default: pony_assert(false); } // Do not duplicate the body and docstring. bool dup_child[9] = {true, true, true, true, true, true, false, false, true}; ast_t* r_ast = ast_dup_partial(ast, dup_child, true, true, true); return reify(r_ast, typeparams, typeargs, opt, false); }
static bool is_nominal_sub_trait(ast_t* sub, ast_t* super) { ast_t* sub_def = (ast_t*)ast_data(sub); // Get our typeparams and typeargs. ast_t* typeparams = ast_childidx(sub_def, 1); ast_t* typeargs = ast_childidx(sub, 2); // Check traits, depth first. ast_t* traits = ast_childidx(sub_def, 3); ast_t* trait = ast_child(traits); while(trait != NULL) { // Reify the trait with our typeargs. ast_t* r_trait = reify(typeargs, trait, typeparams, typeargs); if(r_trait == NULL) return false; // Use the cap and ephemerality of the subtype. AST_GET_CHILDREN(sub, pkg, name, typeparams, cap, eph); ast_t* rr_trait = set_cap_and_ephemeral(r_trait, ast_id(cap), ast_id(eph)); if(rr_trait != r_trait) { ast_free_unattached(r_trait); r_trait = rr_trait; } bool is_sub = is_subtype(r_trait, super); ast_free_unattached(r_trait); if(is_sub) return true; trait = ast_sibling(trait); } return false; }
static ast_t* get_fun(ast_t* type, const char* name, ast_t* typeargs) { ast_t* this_type = set_cap_and_ephemeral(type, TK_REF, TK_NONE); ast_t* fun = lookup(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(fun, typeparams, typeargs); ast_free_unattached(fun); fun = r_fun; assert(fun != NULL); } // No signature for any function with a tuple argument or return value, or // any function that might raise an error. AST_GET_CHILDREN(fun, cap, id, typeparams, params, result, can_error); if(ast_id(can_error) == TK_QUESTION) return NULL; if(ast_id(result) == TK_TUPLETYPE) return NULL; ast_t* param = ast_child(params); while(param != NULL) { AST_GET_CHILDREN(param, p_id, p_type); if(ast_id(p_type) == TK_TUPLETYPE) return NULL; param = ast_sibling(param); } return fun; }
static bool is_fun_sub_fun(ast_t* sub, ast_t* super, ast_t* isub, ast_t* isuper) { token_id tsub = ast_id(sub); token_id tsuper = ast_id(super); switch(tsub) { case TK_NEW: case TK_BE: case TK_FUN: break; default: return false; } switch(tsuper) { case TK_NEW: case TK_BE: case TK_FUN: break; default: return false; } // A constructor can only be a subtype of a constructor. if(((tsub == TK_NEW) || (tsuper == TK_NEW)) && (tsub != tsuper)) return false; AST_GET_CHILDREN(sub, sub_cap, sub_id, sub_typeparams, sub_params); AST_GET_CHILDREN(super, super_cap, super_id, super_typeparams, super_params); // Must have the same name. if(ast_name(sub_id) != ast_name(super_id)) return false; // Must have the same number of type parameters and parameters. if((ast_childcount(sub_typeparams) != ast_childcount(super_typeparams)) || (ast_childcount(sub_params) != ast_childcount(super_params))) return false; ast_t* r_sub = sub; if(ast_id(super_typeparams) != TK_NONE) { // Reify sub with the type parameters of super. BUILD(typeargs, super_typeparams, NODE(TK_TYPEARGS)); ast_t* super_typeparam = ast_child(super_typeparams); while(super_typeparam != NULL) { AST_GET_CHILDREN(super_typeparam, super_id, super_constraint); token_id cap = cap_from_constraint(super_constraint); BUILD(typearg, super_typeparam, NODE(TK_TYPEPARAMREF, TREE(super_id) NODE(cap) NONE)); ast_t* def = ast_get(super_typeparam, ast_name(super_id), NULL); ast_setdata(typearg, def); ast_append(typeargs, typearg); super_typeparam = ast_sibling(super_typeparam); } r_sub = reify(sub, sub, sub_typeparams, typeargs); ast_free_unattached(typeargs); } bool ok = is_reified_fun_sub_fun(r_sub, super, isub, isuper); if(r_sub != sub) ast_free_unattached(r_sub); return ok; }
static void setup_type_fields(gentype_t* g) { assert(ast_id(g->ast) == TK_NOMINAL); g->field_count = 0; g->fields = NULL; g->field_keys = NULL; ast_t* def = (ast_t*)ast_data(g->ast); if(ast_id(def) == TK_PRIMITIVE) return; ast_t* typeargs = ast_childidx(g->ast, 2); ast_t* typeparams = ast_childidx(def, 1); ast_t* members = ast_childidx(def, 4); ast_t* member = ast_child(members); while(member != NULL) { switch(ast_id(member)) { case TK_FVAR: case TK_FLET: case TK_EMBED: { g->field_count++; break; } default: {} } member = ast_sibling(member); } if(g->field_count == 0) return; g->fields = (ast_t**)calloc(g->field_count, sizeof(ast_t*)); g->field_keys = (token_id*)calloc(g->field_count, sizeof(token_id)); member = ast_child(members); size_t index = 0; while(member != NULL) { switch(ast_id(member)) { case TK_FVAR: case TK_FLET: case TK_EMBED: { AST_GET_CHILDREN(member, name, type, init); g->fields[index] = reify(ast_type(member), typeparams, typeargs); // TODO: Are we sure the AST source file is correct? ast_setpos(g->fields[index], NULL, ast_line(name), ast_pos(name)); g->field_keys[index] = ast_id(member); index++; break; } default: {} } member = ast_sibling(member); } }
static ast_t* lookup_nominal(pass_opt_t* opt, ast_t* from, ast_t* orig, ast_t* type, const char* name, bool errors) { assert(ast_id(type) == TK_NOMINAL); typecheck_t* t = &opt->check; ast_t* def = (ast_t*)ast_data(type); AST_GET_CHILDREN(def, type_id, typeparams); const char* type_name = ast_name(type_id); if((type_name[0] == '_') && (from != NULL) && (opt != NULL)) { if(ast_nearest(def, TK_PACKAGE) != t->frame->package) { if(errors) { ast_error(from, "can't lookup fields or methods on private types from other packages" ); } return NULL; } } ast_t* find = ast_get(def, name, NULL); if(find != NULL) { switch(ast_id(find)) { case TK_FVAR: case TK_FLET: case TK_EMBED: break; case TK_NEW: case TK_BE: case TK_FUN: { // Typecheck default args immediately. if(opt != NULL) { AST_GET_CHILDREN(find, cap, id, typeparams, params); ast_t* param = ast_child(params); while(param != NULL) { AST_GET_CHILDREN(param, name, type, def_arg); if((ast_id(def_arg) != TK_NONE) && (ast_type(def_arg) == NULL)) { ast_settype(def_arg, ast_from(def_arg, TK_INFERTYPE)); if(ast_visit_scope(&def_arg, NULL, pass_expr, opt, PASS_EXPR) != AST_OK) return false; ast_visit_scope(&def_arg, NULL, pass_nodebug, opt, PASS_ALL); } param = ast_sibling(param); } } break; } default: find = NULL; } } if(find == NULL) { if(errors) ast_error(from, "couldn't find '%s' in '%s'", name, type_name); return NULL; } if((name[0] == '_') && (from != NULL) && (opt != NULL)) { switch(ast_id(find)) { case TK_FVAR: case TK_FLET: case TK_EMBED: if(t->frame->type != def) { if(errors) { ast_error(from, "can't lookup private fields from outside the type"); } return NULL; } break; case TK_NEW: case TK_BE: case TK_FUN: { if(ast_nearest(def, TK_PACKAGE) != t->frame->package) { if(errors) { ast_error(from, "can't lookup private methods from outside the package"); } return NULL; } break; } default: assert(0); return NULL; } if(!strcmp(name, "_final")) { switch(ast_id(find)) { case TK_NEW: case TK_BE: case TK_FUN: if(errors) ast_error(from, "can't lookup a _final function"); return NULL; default: {} } } } ast_t* typeargs = ast_childidx(type, 2); ast_t* r_find = viewpoint_replacethis(find, orig); ast_t* rr_find = reify(r_find, typeparams, typeargs); ast_free_unattached(r_find); return rr_find; }
bool check_constraints(ast_t* orig, ast_t* typeparams, ast_t* typeargs, bool report_errors, pass_opt_t* opt) { ast_t* typeparam = ast_child(typeparams); ast_t* typearg = ast_child(typeargs); while(typeparam != NULL) { if(ast_id(typearg) == TK_TYPEPARAMREF) { ast_t* def = (ast_t*)ast_data(typearg); if(def == typeparam) { typeparam = ast_sibling(typeparam); typearg = ast_sibling(typearg); continue; } } // Reify the constraint. ast_t* constraint = ast_childidx(typeparam, 1); ast_t* bind_constraint = bind_type(constraint); ast_t* r_constraint = reify(bind_constraint, typeparams, typeargs, opt); if(bind_constraint != r_constraint) ast_free_unattached(bind_constraint); // A bound type must be a subtype of the constraint. errorframe_t info = NULL; if(!is_subtype(typearg, r_constraint, report_errors ? &info : NULL, opt)) { if(report_errors) { ast_error(opt->check.errors, orig, "type argument is outside its constraint"); ast_error_continue(opt->check.errors, typearg, "argument: %s", ast_print_type(typearg)); ast_error_continue(opt->check.errors, typeparam, "constraint: %s", ast_print_type(r_constraint)); } ast_free_unattached(r_constraint); return false; } ast_free_unattached(r_constraint); // A constructable constraint can only be fulfilled by a concrete typearg. if(is_constructable(constraint) && !is_concrete(typearg)) { if(report_errors) { ast_error(opt->check.errors, orig, "a constructable constraint can " "only be fulfilled by a concrete type argument"); ast_error_continue(opt->check.errors, typearg, "argument: %s", ast_print_type(typearg)); ast_error_continue(opt->check.errors, typeparam, "constraint: %s", ast_print_type(constraint)); } return false; } typeparam = ast_sibling(typeparam); typearg = ast_sibling(typearg); } assert(typeparam == NULL); assert(typearg == NULL); return true; }
void test(int initial) { // We jump _down_ the stack to reify() several times with new return values show(" the value is", reify(root, cont, initial)); }
// Add all methods from the provides list of the given entity into lists in the // given symbol table. static bool collate_provided(ast_t* entity, methods_t* method_info) { assert(entity != NULL); bool r = true; ast_t* traits = ast_childidx(entity, 3); for(ast_t* t = ast_child(traits); t != NULL; t = ast_sibling(t)) { assert(ast_id(t) == TK_NOMINAL); ast_t* trait_def = (ast_t*)ast_data(t); assert(trait_def != NULL); // TODO: Check whether we need an error here if((ast_id(trait_def) != TK_TRAIT) && (ast_id(trait_def) != TK_INTERFACE)) return false; // Check for duplicates in our provides list // This is just simple compare of each entry against all the other. This is // clearly O(n^2), but since provides lists are likely to be small that // should be OK. If it turns out to be a problem it can be changed later. for(ast_t* p = ast_child(traits); p != t; p = ast_sibling(p)) { if(trait_def == (ast_t*)ast_data(p)) { ast_error(t, "duplicate entry in provides list"); ast_error(p, "previous entry here"); } } if(!build_entity_def(trait_def)) return false; ast_t* type_params = ast_childidx(trait_def, 1); ast_t* type_args = ast_childidx(t, 2); ast_t* trait_methods = ast_childidx(trait_def, 4); for(ast_t* m = ast_child(trait_methods); m != NULL; m = ast_sibling(m)) { // Reify the method with the type parameters from trait definition and // the reified type arguments from trait reference ast_t* r_method = reify(m, type_params, type_args); const char* entity_name = ast_name(ast_child(entity)); if(ast_id(r_method) == TK_BE || ast_id(r_method) == TK_NEW) { // Modify return type to the inheritting type ast_t* ret_type = ast_childidx(r_method, 4); assert(ast_id(ret_type) == TK_NOMINAL); const char* pkg_name = package_name(ast_nearest(entity, TK_PACKAGE)); ast_set_name(ast_childidx(ret_type, 0), pkg_name); ast_set_name(ast_childidx(ret_type, 1), entity_name); } if(!add_method_to_list(r_method, method_info, entity_name)) r = false; } } return r; }
string string_() { return concat(reify(get()).format(2),"s"); }
static void add_fields(reach_t* r, reach_type_t* t, pass_opt_t* opt) { ast_t* def = (ast_t*)ast_data(t->ast); ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typeparams = ast_childidx(def, 1); ast_t* members = ast_childidx(def, 4); ast_t* member = ast_child(members); while(member != NULL) { switch(ast_id(member)) { case TK_FVAR: case TK_FLET: case TK_EMBED: { t->field_count++; break; } default: {} } member = ast_sibling(member); } if(t->field_count == 0) return; t->fields = (reach_field_t*)calloc(t->field_count, sizeof(reach_field_t)); member = ast_child(members); size_t index = 0; while(member != NULL) { switch(ast_id(member)) { case TK_FVAR: case TK_FLET: case TK_EMBED: { ast_t* r_member = lookup(NULL, NULL, t->ast, ast_name(ast_child(member))); assert(r_member != NULL); AST_GET_CHILDREN(r_member, name, type, init); t->fields[index].embed = ast_id(member) == TK_EMBED; t->fields[index].ast = reify(ast_type(member), typeparams, typeargs, opt, true); ast_setpos(t->fields[index].ast, NULL, ast_line(name), ast_pos(name)); t->fields[index].type = add_type(r, type, opt); if(r_member != member) ast_free_unattached(r_member); index++; break; } default: {} } member = ast_sibling(member); } }
static ast_t* lookup_nominal(typecheck_t* t, ast_t* from, ast_t* orig, ast_t* type, const char* name, bool errors) { assert(ast_id(type) == TK_NOMINAL); ast_t* def = (ast_t*)ast_data(type); ast_t* type_name = ast_child(def); ast_t* find = ast_get(def, name, NULL); if(find != NULL) { switch(ast_id(find)) { case TK_FVAR: case TK_FLET: case TK_NEW: case TK_BE: case TK_FUN: break; default: find = NULL; } } if(find == NULL) { if(errors) ast_error(from, "couldn't find '%s' in '%s'", name, ast_name(type_name)); return NULL; } if((name[0] == '_') && (from != NULL) && (t != NULL)) { switch(ast_id(find)) { case TK_FVAR: case TK_FLET: if(t->frame->type != def) { if(errors) { ast_error(from, "can't lookup private fields from outside the type"); } return NULL; } break; case TK_NEW: case TK_BE: case TK_FUN: { if(ast_nearest(def, TK_PACKAGE) != t->frame->package) { if(errors) { ast_error(from, "can't lookup private methods from outside the package"); } return NULL; } break; } default: assert(0); return NULL; } if(!strcmp(name, "_final")) { switch(ast_id(find)) { case TK_NEW: case TK_BE: case TK_FUN: if(errors) ast_error(from, "can't lookup a _final function"); return NULL; default: {} } } } ast_t* typeparams = ast_sibling(type_name); ast_t* typeargs = ast_childidx(type, 2); find = ast_dup(find); orig = ast_dup(orig); replace_thistype(&find, orig); ast_free_unattached(orig); ast_t* r_find = reify(from, find, typeparams, typeargs); if(r_find != find) { ast_free_unattached(find); find = r_find; } if((find != NULL) && !flatten_arrows(&find, errors)) { if(errors) ast_error(from, "can't look this up on a tag"); ast_free_unattached(find); return NULL; } return find; }
auto clone(auto& value) { return reify(value); }
bool expr_qualify(pass_opt_t* opt, ast_t** astp) { // Left is a postfix expression, right is a typeargs. ast_t* ast = *astp; AST_GET_CHILDREN(ast, left, right); ast_t* type = ast_type(left); assert(ast_id(right) == TK_TYPEARGS); if(is_typecheck_error(type)) return false; switch(ast_id(left)) { case TK_TYPEREF: { // Qualify the type. assert(ast_id(type) == TK_NOMINAL); // If the type isn't polymorphic or the type is already qualified, // sugar .apply(). ast_t* def = names_def(opt, type); ast_t* typeparams = ast_childidx(def, 1); if((ast_id(typeparams) == TK_NONE) || (ast_id(ast_childidx(type, 2)) != TK_NONE)) { if(!expr_nominal(opt, &type)) return false; break; } type = ast_dup(type); ast_t* typeargs = ast_childidx(type, 2); ast_replace(&typeargs, right); ast_settype(ast, type); ast_setid(ast, TK_TYPEREF); return expr_typeref(opt, astp); } case TK_NEWREF: case TK_NEWBEREF: case TK_BEREF: case TK_FUNREF: case TK_NEWAPP: case TK_BEAPP: case TK_FUNAPP: { // Qualify the function. assert(ast_id(type) == TK_FUNTYPE); ast_t* typeparams = ast_childidx(type, 1); if(!reify_defaults(typeparams, right, true, opt)) return false; if(!check_constraints(left, typeparams, right, true, opt)) return false; type = reify(type, typeparams, right, opt); typeparams = ast_childidx(type, 1); ast_replace(&typeparams, ast_from(typeparams, TK_NONE)); ast_settype(ast, type); ast_setid(ast, ast_id(left)); ast_inheritflags(ast); return true; } default: {} } // Sugar .apply() ast_t* dot = ast_from(left, TK_DOT); ast_add(dot, ast_from_string(left, "apply")); ast_swap(left, dot); ast_add(dot, left); if(!expr_dot(opt, &dot)) return false; return expr_qualify(opt, astp); }
bool check_constraints(ast_t* orig, ast_t* typeparams, ast_t* typeargs, bool report_errors) { ast_t* typeparam = ast_child(typeparams); ast_t* typearg = ast_child(typeargs); while(typeparam != NULL) { // Reify the constraint. ast_t* constraint = ast_childidx(typeparam, 1); ast_t* bind_constraint = bind_type(constraint); ast_t* r_constraint = reify(bind_constraint, typeparams, typeargs); if(bind_constraint != r_constraint) ast_free_unattached(bind_constraint); // A bound type must be a subtype of the constraint. errorframe_t info = NULL; if(!is_subtype(typearg, r_constraint, report_errors ? &info : NULL)) { if(report_errors) { errorframe_t frame = NULL; ast_error_frame(&frame, orig, "type argument is outside its constraint"); ast_error_frame(&frame, typearg, "argument: %s", ast_print_type(typearg)); ast_error_frame(&frame, typeparam, "constraint: %s", ast_print_type(r_constraint)); errorframe_append(&frame, &info); errorframe_report(&frame); } ast_free_unattached(r_constraint); return false; } ast_free_unattached(r_constraint); // A constructable constraint can only be fulfilled by a concrete typearg. if(is_constructable(constraint) && !is_concrete(typearg)) { if(report_errors) { ast_error(orig, "a constructable constraint can only be fulfilled " "by a concrete type argument"); ast_error(typearg, "argument: %s", ast_print_type(typearg)); ast_error(typeparam, "constraint: %s", ast_print_type(constraint)); } return false; } typeparam = ast_sibling(typeparam); typearg = ast_sibling(typearg); } assert(typeparam == NULL); assert(typearg == NULL); return true; }