bool expr_nominal(pass_opt_t* opt, ast_t** astp) { // Resolve typealiases and typeparam references. if(!names_nominal(opt, *astp, astp)) return false; ast_t* ast = *astp; switch(ast_id(ast)) { case TK_TYPEPARAMREF: return flatten_typeparamref(ast) == AST_OK; case TK_NOMINAL: break; default: return true; } // If still nominal, check constraints. ast_t* def = (ast_t*)ast_data(ast); // Special case: don't check the constraint of a Pointer. This allows a // Pointer[Pointer[A]], which is normally not allowed, as a Pointer[A] is // not a subtype of Any. ast_t* id = ast_child(def); const char* name = ast_name(id); if(!strcmp(name, "Pointer")) return true; ast_t* typeparams = ast_childidx(def, 1); ast_t* typeargs = ast_childidx(ast, 2); return check_constraints(typeargs, typeparams, typeargs, true); }
// Process the methods required for delegation to all the fields in the given // entity. static bool delegated_methods(ast_t* entity, pass_opt_t* opt) { assert(entity != NULL); bool r = true; // Check all fields. for(ast_t* field = ast_child(ast_childidx(entity, 4)); field != NULL; field = ast_sibling(field)) { if(is_field(field)) { AST_GET_CHILDREN(field, id, f_type, value, delegates); // Check all delegates for field. for(ast_t* trait_ref = ast_child(delegates); trait_ref != NULL; trait_ref = ast_sibling(trait_ref)) { ast_t* trait = (ast_t*)ast_data(trait_ref); assert(trait != NULL); if(!trait_entity(trait, opt)) return false; // Run through the methods of each delegated type. for(ast_t* method = ast_child(ast_childidx(trait, 4)); method != NULL; method = ast_sibling(method)) { if(!delegated_method(entity, method, field, trait_ref, opt)) r = false; } } } } return r; }
static bool check_type_params(pass_opt_t* opt, 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(!reify_defaults(typeparams, typeargs, true, opt)) { ast_free_unattached(typeargs); return false; } if(!check_constraints(lhs, typeparams, typeargs, true, opt)) { ast_free_unattached(typeargs); return false; } type = reify(type, typeparams, typeargs, opt); 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; }
static void add_dispatch_case(compile_t* c, gentype_t* g, ast_t* fun, uint32_t index, LLVMValueRef handler, LLVMTypeRef type) { // Add a case to the dispatch function to handle this message. codegen_startfun(c, g->dispatch_fn, false); LLVMBasicBlockRef block = codegen_block(c, "handler"); LLVMValueRef id = LLVMConstInt(c->i32, index, false); LLVMAddCase(g->dispatch_switch, id, block); // Destructure the message. LLVMPositionBuilderAtEnd(c->builder, block); LLVMValueRef ctx = LLVMGetParam(g->dispatch_fn, 0); LLVMValueRef this_ptr = LLVMGetParam(g->dispatch_fn, 1); LLVMValueRef msg = LLVMBuildBitCast(c->builder, LLVMGetParam(g->dispatch_fn, 2), type, ""); int count = LLVMCountParams(handler); size_t buf_size = count * sizeof(LLVMValueRef); LLVMValueRef* args = (LLVMValueRef*)pool_alloc_size(buf_size); args[0] = LLVMBuildBitCast(c->builder, this_ptr, g->use_type, ""); // Trace the message. LLVMValueRef start_trace = gencall_runtime(c, "pony_gc_recv", &ctx, 1, ""); ast_t* params = ast_childidx(fun, 3); ast_t* param = ast_child(params); bool need_trace = false; for(int i = 1; i < count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, msg, i + 2, ""); args[i] = LLVMBuildLoad(c->builder, field, ""); need_trace |= gentrace(c, ctx, args[i], ast_type(param)); param = ast_sibling(param); } if(need_trace) { gencall_runtime(c, "pony_recv_done", &ctx, 1, ""); } else { LLVMInstructionEraseFromParent(start_trace); } // Call the handler. codegen_call(c, handler, args, count); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); pool_free_size(buf_size, args); }
// The subtype is a typeparam, the supertype could be anything. static bool is_typeparam_subtype(ast_t* sub, ast_t* super) { switch(ast_id(super)) { case TK_TYPEPARAMREF: if(is_typeparam_sub_typeparam(sub, super)) return true; break; case TK_UNIONTYPE: if(is_subtype_union(sub, super)) return true; break; case TK_ISECTTYPE: if(is_subtype_isect(sub, super)) return true; break; case TK_ARROW: if(is_subtype_arrow(sub, super)) return true; break; default: {} } // We can be a subtype if our upper bounds, ie our constraint, is a subtype. ast_t* sub_def = (ast_t*)ast_data(sub); ast_t* constraint = ast_childidx(sub_def, 1); if(ast_id(constraint) == TK_TYPEPARAMREF) { ast_t* constraint_def = (ast_t*)ast_data(constraint); if(constraint_def == sub_def) return false; } // Constraint must be modified with sub ephemerality. AST_GET_CHILDREN(sub, name, cap, eph); ast_t* r_constraint = set_cap_and_ephemeral(constraint, TK_NONE, ast_id(eph)); bool ok = is_subtype(r_constraint, super); ast_free_unattached(r_constraint); return ok; }
static bool capture_from_type(pass_opt_t* opt, ast_t* ctx, ast_t** def, ast_t* capture, ast_t** last_capture) { // Turn any free variables into fields. if(!ast_passes_type(def, opt, PASS_SCOPE)) return false; bool ok = true; ast_t* members = ast_childidx(*def, 4); for(ast_t* p = ast_child(members); p != NULL; p = ast_sibling(p)) { switch(ast_id(p)) { case TK_FUN: case TK_BE: { if(ast_id(ast_child(p)) != TK_AT) { ast_t* body = ast_childidx(p, 6); if(!capture_from_expr(opt, ctx, body, capture, last_capture)) ok = false; } break; } default: {} } } // Reset the scope. ast_clear(*def); return ok; }
static void trace_array_elements(compile_t* c, reach_type_t* t, LLVMValueRef ctx, LLVMValueRef object, LLVMValueRef pointer) { // Get the type argument for the array. This will be used to generate the // per-element trace call. ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); if(!gentrace_needed(typearg)) return; reach_type_t* t_elem = reach_type(c->reach, typearg); pointer = LLVMBuildBitCast(c->builder, pointer, LLVMPointerType(t_elem->use_type, 0), ""); LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef cond_block = codegen_block(c, "cond"); LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); // Read the size. LLVMValueRef size = field_value(c, object, 1); LLVMBuildBr(c->builder, cond_block); // While the index is less than the size, trace an element. The initial // index when coming from the entry block is zero. LLVMPositionBuilderAtEnd(c->builder, cond_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->intptr, ""); LLVMValueRef zero = LLVMConstInt(c->intptr, 0, false); LLVMAddIncoming(phi, &zero, &entry_block, 1); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntULT, phi, size, ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); // The phi node is the index. Get the element and trace it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef elem_ptr = LLVMBuildGEP(c->builder, pointer, &phi, 1, "elem"); LLVMValueRef elem = LLVMBuildLoad(c->builder, elem_ptr, ""); gentrace(c, ctx, elem, typearg); // Add one to the phi node and branch back to the cond block. LLVMValueRef one = LLVMConstInt(c->intptr, 1, false); LLVMValueRef inc = LLVMBuildAdd(c->builder, phi, one, ""); body_block = LLVMGetInsertBlock(c->builder); LLVMAddIncoming(phi, &inc, &body_block, 1); LLVMBuildBr(c->builder, cond_block); LLVMPositionBuilderAtEnd(c->builder, post_block); }
static bool reachable_actors(compile_t* c, ast_t* program) { // Look for C-API actors in every package. bool found = false; ast_t* package = ast_child(program); while(package != NULL) { ast_t* module = ast_child(package); while(module != NULL) { ast_t* entity = ast_child(module); while(entity != NULL) { if(ast_id(entity) == TK_ACTOR) { ast_t* c_api = ast_childidx(entity, 5); if(ast_id(c_api) == TK_AT) { // We have an actor marked as C-API. if(!reachable_methods(c, entity)) return false; found = true; } } entity = ast_sibling(entity); } module = ast_sibling(module); } package = ast_sibling(package); } if(!found) { errorf(NULL, "no C-API actors found in package '%s'", c->filename); return false; } paint(c->reachable); return true; }
LLVMValueRef gen_error(compile_t* c, ast_t* ast) { size_t clause; ast_t* try_expr = ast_try_clause(ast, &clause); // Do the then block only if we error out in the else clause. if((try_expr != NULL) && (clause == 1)) gen_expr(c, ast_childidx(try_expr, 2)); codegen_scope_lifetime_end(c); codegen_debugloc(c, ast); gencall_throw(c); codegen_debugloc(c, NULL); return GEN_NOVALUE; }
static ast_result_t sugar_use(ast_t* ast) { assert(ast != NULL); // Normalise condition so and, or and not nodes aren't sugared to function // calls. ast_t* guard = ast_childidx(ast, 2); if(!ifdef_cond_normalise(&guard)) { ast_error(ast, "use guard condition will never be true"); return AST_ERROR; } return AST_OK; }
static bool check_main_create(typecheck_t* t, ast_t* ast) { if(ast_id(t->frame->type) != TK_ACTOR) return true; ast_t* type_id = ast_child(t->frame->type); if(strcmp(ast_name(type_id), "Main")) return true; AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error); if(strcmp(ast_name(id), "create")) return true; bool ok = true; if(ast_id(typeparams) != TK_NONE) { ast_error(typeparams, "the create constructor of a Main actor must not be polymorphic"); ok = false; } if(ast_childcount(params) != 1) { ast_error(params, "the create constructor of a Main actor must take a single Env " "parameter"); ok = false; } ast_t* param = ast_child(params); if(param != NULL) { ast_t* p_type = ast_childidx(param, 1); if(!is_env(p_type)) { ast_error(p_type, "must be of type Env"); ok = false; } } return ok; }
// Resolve all methods in the given type. // Stage 4. static bool resolve_methods(ast_t* ast, pass_opt_t* options) { assert(ast != NULL); ast_t* members = ast_childidx(ast, 4); assert(members != NULL); bool r = true; for(ast_t* p = ast_child(members); p != NULL; p = ast_sibling(p)) { if(is_method(p) && !resolve_body(ast, p, options)) r = false; } return r; }
static matchtype_t could_subtype_typeparam(ast_t* sub, ast_t* super) { switch(ast_id(super)) { case TK_NOMINAL: { // If our constraint could be a subtype of super, some reifications could // be a subtype of super. ast_t* sub_def = (ast_t*)ast_data(sub); ast_t* constraint = ast_childidx(sub_def, 1); if(ast_id(constraint) == TK_TYPEPARAMREF) { ast_t* constraint_def = (ast_t*)ast_data(constraint); if(constraint_def == sub_def) return MATCHTYPE_REJECT; } return could_subtype(constraint, super); } case TK_UNIONTYPE: return could_subtype_with_union(sub, super); case TK_ISECTTYPE: return could_subtype_with_isect(sub, super); case TK_TUPLETYPE: // A type parameter can't be constrained to a tuple. return MATCHTYPE_REJECT; case TK_ARROW: return could_subtype_with_arrow(sub, super); case TK_TYPEPARAMREF: // If the supertype is a typeparam, we have to be a subtype. return could_subtype_or_deny(sub, super); default: {} } assert(0); return MATCHTYPE_DENY; }
// Flatten a provides type into a list, checking all types are traits or // interfaces static ast_result_t flatten_provides_list(ast_t* provider, int index) { assert(provider != NULL); ast_t* provides = ast_childidx(provider, index); ast_t* list = ast_from(provides, TK_PROVIDES); ast_t* list_end = NULL; if(ast_id(provides) != TK_NONE && !flatten_provided_type(provides, provider, list, &list_end)) { ast_free(list); return AST_ERROR; } ast_replace(&provides, list); return AST_OK; }
static void trace_maybe(compile_t* c, LLVMValueRef ctx, LLVMValueRef object, ast_t* type) { // Only trace the element if it isn't NULL. ast_t* type_args = ast_childidx(type, 2); ast_t* elem = ast_child(type_args); LLVMValueRef test = LLVMBuildIsNull(c->builder, object, ""); LLVMBasicBlockRef is_false = codegen_block(c, ""); LLVMBasicBlockRef is_true = codegen_block(c, ""); LLVMBuildCondBr(c->builder, test, is_true, is_false); LLVMPositionBuilderAtEnd(c->builder, is_false); gentrace(c, ctx, object, elem); LLVMBuildBr(c->builder, is_true); LLVMPositionBuilderAtEnd(c->builder, is_true); }
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 tuple_access(pass_opt_t* opt, ast_t* ast) { // Left is a postfix expression, right is a lookup name. 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; // Change the lookup name to an integer index. if(!make_tuple_index(&right)) { ast_error(opt->check.errors, right, "lookup on a tuple must take the form _X, where X is an integer"); return false; } // Make sure our index is in bounds. make_tuple_index automatically shifts // from one indexed to zero, so we have to use -1 and >= for our comparisons. size_t right_idx = (size_t)ast_int(right)->low; size_t tuple_size = ast_childcount(type); if (right_idx == (size_t)-1) { ast_error(opt->check.errors, right, "tuples are one indexed not zero indexed. Did you mean _1?"); return false; } else if (right_idx >= tuple_size) { ast_error(opt->check.errors, right, "tuple index " __zu " is out of " "valid range. Valid range is [1, " __zu "]", right_idx, tuple_size); return false; } type = ast_childidx(type, right_idx); assert(type != NULL); ast_setid(ast, TK_FLETREF); ast_settype(ast, type); ast_inheritflags(ast); return true; }
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; }
// Add the given method to the relevant name list in the given symbol table static bool add_method_to_list(ast_t* method, methods_t* method_info, const char *entity_name) { assert(method != NULL); assert(method_info != NULL); assert(entity_name != NULL); const char* name = ast_name(ast_childidx(method, 1)); assert(name != NULL); symtab_t* symtab = method_info->symtab; assert(symtab != NULL); // Entity doesn't yet have method, add it to our list for later ast_t* list = (ast_t*)symtab_find(symtab, name, NULL); if(list == NULL) { ast_t* case_clash = (ast_t*)symtab_find_case(symtab, name, NULL); if(case_clash != NULL) { ast_error(case_clash, "in %s method name differs only in case", entity_name); ast_error(method, "previous definition is here"); return false; } // First instance of this name list = ast_blank(TK_ID); ast_set_name(list, name); symtab_add(symtab, name, (void*)list, SYM_NONE); if(method_info->last_list == NULL) ast_add(method_info->name_lists, list); else ast_add_sibling(method_info->last_list, list); method_info->last_list = list; } ast_add(list, method); return true; }
static token_id partial_application_cap(pass_opt_t* opt, ast_t* ftype, ast_t* receiver, ast_t* positional) { // Check if the apply method in the generated object literal can accept a box // receiver. If not, it must be a ref receiver. It can accept a box receiver // if box->receiver <: lhs->receiver and box->arg <: lhs->param. AST_GET_CHILDREN(ftype, cap, typeparams, params, result); ast_t* type = ast_type(receiver); ast_t* view_type = viewpoint_type(ast_from(type, TK_BOX), type); ast_t* need_type = set_cap_and_ephemeral(type, ast_id(cap), TK_NONE); bool ok = is_subtype(view_type, need_type, NULL, opt); ast_free_unattached(view_type); ast_free_unattached(need_type); if(!ok) return TK_REF; ast_t* param = ast_child(params); ast_t* arg = ast_child(positional); while(arg != NULL) { if(ast_id(arg) != TK_NONE) { type = ast_type(arg); view_type = viewpoint_type(ast_from(type, TK_BOX), type); need_type = ast_childidx(param, 1); ok = is_subtype(view_type, need_type, NULL, opt); ast_free_unattached(view_type); ast_free_unattached(need_type); if(!ok) return TK_REF; } arg = ast_sibling(arg); param = ast_sibling(param); } return TK_BOX; }
static ast_result_t syntax_return(pass_opt_t* opt, ast_t* ast, size_t max_value_count) { assert(ast != NULL); ast_t* value_seq = ast_child(ast); assert(ast_id(value_seq) == TK_SEQ || ast_id(value_seq) == TK_NONE); size_t value_count = ast_childcount(value_seq); if(value_count > max_value_count) { ast_error(opt->check.errors, ast_childidx(value_seq, max_value_count), "Unreachable code"); return AST_ERROR; } if(ast_id(ast) == TK_RETURN) { if(opt->check.frame->method_body == NULL) { ast_error(opt->check.errors, ast, "return must occur in a method body"); return AST_ERROR; } if(value_count > 0) { if(ast_id(opt->check.frame->method) == TK_NEW) { ast_error(opt->check.errors, ast, "A return in a constructor must not have an expression"); return AST_ERROR; } if(ast_id(opt->check.frame->method) == TK_BE) { ast_error(opt->check.errors, ast, "A return in a behaviour must not have an expression"); return AST_ERROR; } } } return AST_OK; }
static bool apply_default_arg(pass_opt_t* opt, ast_t* param, ast_t* arg) { // Pick up a default argument. ast_t* def_arg = ast_childidx(param, 2); if(ast_id(def_arg) == TK_NONE) { ast_error(arg, "not enough arguments"); return false; } ast_setid(arg, TK_SEQ); ast_add(arg, def_arg); if(!expr_seq(opt, arg)) return false; return true; }
void genprim_pointer_methods(compile_t* c, reach_type_t* t) { ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); reach_type_t* t_elem = reach_type(c->reach, typearg); pointer_create(c, t); pointer_alloc(c, t, t_elem); pointer_realloc(c, t, t_elem); pointer_unsafe(c, t); pointer_apply(c, t, t_elem); pointer_update(c, t, t_elem); pointer_offset(c, t, t_elem); pointer_insert(c, t, t_elem); pointer_delete(c, t, t_elem); pointer_copy_to(c, t, t_elem); pointer_usize(c, t); }
static ast_result_t syntax_arrowtype(ast_t* ast) { assert(ast != NULL); ast_t* rhs = ast_childidx(ast, 1); if(ast_child(rhs) == NULL && ast_id(rhs) == TK_THISTYPE) { ast_error(ast, "'this' cannot appear to the right of a viewpoint"); return AST_ERROR; } if(ast_child(rhs) == NULL && ast_id(rhs) == TK_BOXTYPE) { ast_error(ast, "'box' cannot appear to the right of a viewpoint"); return AST_ERROR; } return AST_OK; }
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; }
void dwarf_method(dwarf_t* dwarf, ast_t* fun, const char* name, const char* mangled, const char** params, size_t count, LLVMValueRef ir) { dwarf_meta_t meta; memset(&meta, 0, sizeof(dwarf_meta_t)); source_t* source = ast_source(fun); ast_t* seq = ast_childidx(fun, 6); meta.file = source->file; meta.name = name; meta.mangled = mangled; meta.params = params; meta.line = ast_line(fun); meta.pos = ast_pos(fun); meta.offset = ast_line(seq); meta.size = count; symbols_method(dwarf->symbols, &meta, ir); }
static bool is_assigned_to(ast_t* ast, bool check_result_needed) { while(true) { ast_t* parent = ast_parent(ast); switch(ast_id(parent)) { case TK_ASSIGN: { // Has to be the left hand side of an assignment. Left and right sides // are swapped, so we must be the second child. if(ast_childidx(parent, 1) != ast) return false; if(!check_result_needed) return true; // The result of that assignment can't be used. return !is_result_needed(parent); } case TK_SEQ: { // Might be in a tuple on the left hand side. if(ast_childcount(parent) > 1) return false; break; } case TK_TUPLE: break; default: return false; } ast = parent; } }
// The subtype is a nominal, the super type is a typeparam. static bool is_nominal_sub_typeparam(ast_t* sub, ast_t* super) { // Must be a subtype of the lower bounds of the constraint. ast_t* def = (ast_t*)ast_data(super); ast_t* constraint = ast_childidx(def, 1); if(ast_id(constraint) == TK_NOMINAL) { ast_t* constraint_def = (ast_t*)ast_data(constraint); switch(ast_id(constraint_def)) { case TK_PRIMITIVE: case TK_CLASS: case TK_ACTOR: { // Constraint must be modified with super ephemerality. AST_GET_CHILDREN(super, name, cap, eph); ast_t* r_constraint = set_cap_and_ephemeral(constraint, TK_NONE, ast_id(eph)); // Must be a subtype of the constraint. bool ok = is_subtype(sub, constraint); ast_free_unattached(r_constraint); if(!ok) return false; // Capability must be a subtype of the lower bounds of the typeparam. ast_t* lower = viewpoint_lower(super); ok = is_sub_cap_and_ephemeral(sub, lower); ast_free_unattached(lower); return ok; } default: {} } } return false; }
// Tidy up the method_t structures in the given type static void tidy_up(ast_t* ast) { assert(ast != NULL); ast_t* members = ast_childidx(ast, 4); assert(members != NULL); for(ast_t* p = ast_child(members); p != NULL; p = ast_sibling(p)) { if(is_method(p)) { method_t* info = (method_t*)ast_data(p); assert(info != NULL); ast_t* body_donor = info->body_donor; ast_free_unattached(info->reified_default); POOL_FREE(method_t, info); ast_setdata(p, body_donor); } } }
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; }