static matchtype_t is_tuple_match_tuple(ast_t* operand, ast_t* pattern) { // Must be a pairwise match. if(ast_childcount(operand) != ast_childcount(pattern)) return MATCHTYPE_REJECT; ast_t* operand_child = ast_child(operand); ast_t* pattern_child = ast_child(pattern); matchtype_t ok = MATCHTYPE_ACCEPT; while(operand_child != NULL) { switch(is_matchtype(operand_child, pattern_child)) { case MATCHTYPE_ACCEPT: break; case MATCHTYPE_REJECT: ok = MATCHTYPE_REJECT; break; case MATCHTYPE_DENY: return MATCHTYPE_DENY; } operand_child = ast_sibling(operand_child); pattern_child = ast_sibling(pattern_child); } return ok; }
int subtype_kind_overlap(reach_type_t* left, reach_type_t* right) { int subtypes = SUBTYPE_KIND_NONE; size_t i = HASHMAP_BEGIN; reach_type_t* sub_left; while((sub_left = reach_type_cache_next(&left->subtypes, &i)) != NULL) { if(!sub_left->can_be_boxed) { subtypes |= SUBTYPE_KIND_UNBOXED; if(subtypes == SUBTYPE_KIND_ALL) return subtypes; continue; } if(sub_left->underlying != TK_TUPLETYPE) { reach_type_t k; k.name = sub_left->name; size_t j = HASHMAP_UNKNOWN; reach_type_t* sub_right = reach_type_cache_get(&right->subtypes, &k, &j); if(sub_right != NULL) { pony_assert(sub_left == sub_right); if(sub_left->underlying == TK_PRIMITIVE) subtypes |= SUBTYPE_KIND_NUMERIC; if(subtypes == SUBTYPE_KIND_ALL) return subtypes; } } else if((subtypes & SUBTYPE_KIND_TUPLE) == 0) { size_t cardinality = ast_childcount(sub_left->ast_cap); size_t j = HASHMAP_UNKNOWN; reach_type_t* sub_right; while((sub_right = reach_type_cache_next(&right->subtypes, &j)) != NULL) { if((sub_right->underlying == TK_TUPLETYPE) && (ast_childcount(sub_right->ast_cap) == cardinality)) { subtypes |= SUBTYPE_KIND_TUPLE; if(subtypes == SUBTYPE_KIND_ALL) return subtypes; break; } } } } return subtypes; }
bool reify_defaults(ast_t* typeparams, ast_t* typeargs, bool errors, pass_opt_t* opt) { assert( (ast_id(typeparams) == TK_TYPEPARAMS) || (ast_id(typeparams) == TK_NONE) ); assert( (ast_id(typeargs) == TK_TYPEARGS) || (ast_id(typeargs) == TK_NONE) ); size_t param_count = ast_childcount(typeparams); size_t arg_count = ast_childcount(typeargs); if(param_count == arg_count) return true; if(param_count < arg_count) { if(errors) { ast_error(opt->check.errors, typeargs, "too many type arguments"); ast_error_continue(opt->check.errors, typeparams, "definition is here"); } return false; } // Pick up default type arguments if they exist. ast_setid(typeargs, TK_TYPEARGS); ast_t* typeparam = ast_childidx(typeparams, arg_count); while(typeparam != NULL) { ast_t* defarg = ast_childidx(typeparam, 2); if(ast_id(defarg) == TK_NONE) break; ast_append(typeargs, defarg); typeparam = ast_sibling(typeparam); } if(typeparam != NULL) { if(errors) { ast_error(opt->check.errors, typeargs, "not enough type arguments"); ast_error_continue(opt->check.errors, typeparams, "definition is here"); } return false; } return true; }
ast_t* type_isect_fun(ast_t* a, ast_t* b) { token_id ta = ast_id(a); token_id tb = ast_id(b); if(((ta == TK_NEW) || (tb == TK_NEW)) && (ta != tb)) return NULL; AST_GET_CHILDREN(a, a_cap, a_id, a_typeparams, a_params, a_result, a_throw); AST_GET_CHILDREN(b, b_cap, b_id, b_typeparams, b_params, b_result, b_throw); // Must have the same name. if(ast_name(a_id) != ast_name(b_id)) return NULL; // Must have the same number of type parameters and parameters. if((ast_childcount(a_typeparams) != ast_childcount(b_typeparams)) || (ast_childcount(a_params) != ast_childcount(b_params))) return NULL; // Contravariant receiver cap. token_id tcap; token_id a_tcap = ast_id(a_cap); token_id b_tcap = ast_id(b_cap); if(is_cap_sub_cap(b_tcap, TK_NONE, a_tcap, TK_NONE)) tcap = a_tcap; else if(is_cap_sub_cap(a_tcap, TK_NONE, b_tcap, TK_NONE)) tcap = b_tcap; else tcap = TK_BOX; // Result is the intersection of the results. ast_t* result = type_isect(a_result, b_result); // Covariant throws. token_id throws; if((ast_id(a_throw) == TK_NONE) || (ast_id(b_throw) == TK_NONE)) throws = TK_NONE; else throws = TK_QUESTION; BUILD(fun, a, NODE(tcap) TREE(a_id) NODE(TK_TYPEPARAMS) NODE(TK_PARAMS) TREE(result) NODE(throws) ); // TODO: union typeparams and params // handling typeparam names is tricky return fun; }
static LLVMValueRef tuple_is(compile_t* c, ast_t* left_type, ast_t* right_type, LLVMValueRef l_value, LLVMValueRef r_value) { pony_assert(ast_id(left_type) == TK_TUPLETYPE); pony_assert(ast_id(right_type) == TK_TUPLETYPE); pony_assert(ast_childcount(left_type) == ast_childcount(right_type)); // Pairwise comparison. LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef post_block = codegen_block(c, "post"); // Set up the phi node. LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->i1, ""); ast_t* left_child = ast_child(left_type); ast_t* right_child = ast_child(right_type); int i = 0; while(left_child != NULL) { // Set up the next block. LLVMBasicBlockRef next_block = codegen_block(c, "next"); LLVMPositionBuilderAtEnd(c->builder, this_block); // Test the element. LLVMValueRef l_elem = LLVMBuildExtractValue(c->builder, l_value, i, ""); LLVMValueRef r_elem = LLVMBuildExtractValue(c->builder, r_value, i, ""); LLVMValueRef test = gen_is_value(c, left_child, right_child, l_elem, r_elem); // If false, go directly to the post block. LLVMBuildCondBr(c->builder, test, next_block, post_block); LLVMBasicBlockRef current_block = LLVMGetInsertBlock(c->builder); LLVMAddIncoming(phi, &test, ¤t_block, 1); // Point to the next block. this_block = next_block; left_child = ast_sibling(left_child); right_child = ast_sibling(right_child); i++; } // The last block is reached if every element returns true. Jump directly to // the post block. LLVMPositionBuilderAtEnd(c->builder, this_block); LLVMBuildBr(c->builder, post_block); LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMValueRef one = LLVMConstInt(c->i1, 1, false); LLVMAddIncoming(phi, &one, &this_block, 1); return phi; }
static void type_append(printbuf_t* buf, ast_t* type, bool first) { switch(ast_id(type)) { case TK_UNIONTYPE: { // u3_Arg1_Arg2_Arg3 printbuf(buf, "u%d", ast_childcount(type)); types_append(buf, type); return; } case TK_ISECTTYPE: { // i3_Arg1_Arg2_Arg3 printbuf(buf, "i%d", ast_childcount(type)); types_append(buf, type); return; } case TK_TUPLETYPE: { // t3_Arg1_Arg2_Arg3 printbuf(buf, "t%d", ast_childcount(type)); types_append(buf, type); return; } case TK_NOMINAL: { // pkg_Type[_Arg1_Arg2]_cap AST_GET_CHILDREN(type, package, name, typeargs, cap, eph); ast_t* def = (ast_t*)ast_data(type); ast_t* pkg = ast_nearest(def, TK_PACKAGE); const char* pkg_name = package_symbol(pkg); if(pkg_name != NULL) printbuf(buf, "%s_", pkg_name); printbuf(buf, "%s", ast_name(name)); types_append(buf, typeargs); if(!first) printbuf(buf, "_%s", ast_get_print(cap)); return; } default: {} } assert(0); }
// Determine the UIF types that the given type may be static int uifset(pass_opt_t* opt, ast_t* type, lit_chain_t* chain) { assert(chain != NULL); if(is_typecheck_error(type)) return UIF_NO_TYPES; switch(ast_id(type)) { case TK_UNIONTYPE: return uifset_union(opt, type, chain); case TK_ISECTTYPE: return uifset_intersect(opt, type, chain); case TK_ARROW: // Since we don't care about capabilities we can just use the rhs assert(ast_id(ast_childidx(type, 1)) == TK_NOMINAL); return uifset(opt, ast_childidx(type, 1), chain); case TK_TYPEPARAMREF: if(chain->cardinality != CHAIN_CARD_BASE) // Incorrect cardinality return UIF_NO_TYPES; return uifset_formal_param(opt, type, chain); case TK_TUPLETYPE: if(chain->cardinality != ast_childcount(type)) // Incorrect cardinality return UIF_NO_TYPES; return uifset(opt, ast_childidx(type, chain->index), chain->next); case TK_NOMINAL: if(strcmp(ast_name(ast_childidx(type, 1)), "Array") == 0) { if(chain->cardinality != CHAIN_CARD_ARRAY) // Incorrect cardinality return UIF_NO_TYPES; ast_t* type_args = ast_childidx(type, 2); assert(ast_childcount(type_args) == 1); return uifset(opt, ast_child(type_args), chain->next); } if(chain->cardinality != CHAIN_CARD_BASE) // Incorrect cardinality return UIF_NO_TYPES; return uifset_simple_type(opt, type); default: ast_error(type, "Internal error: uif type, node %d", ast_id(type)); assert(0); return UIF_ERROR; } }
static void handle_stack(reachable_method_stack_t* s, reachable_types_t* r, uint32_t* next_type_id) { while(s != NULL) { reachable_method_t* m; s = reachable_method_stack_pop(s, &m); AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error, body); m->param_count = ast_childcount(params); m->params = (reachable_type_t**)ponyint_pool_alloc_size( m->param_count * sizeof(reachable_type_t*)); ast_t* param = ast_child(params); size_t i = 0; while(param != NULL) { AST_GET_CHILDREN(param, p_id, p_type); m->params[i++] = add_type(&s, r, next_type_id, p_type); param = ast_sibling(param); } m->result = add_type(&s, r, next_type_id, result); reachable_expr(&s, r, next_type_id, body); } }
static ast_result_t flatten_isect(pass_opt_t* opt, ast_t* ast) { // Flatten intersections without testing subtyping. This is to preserve any // type guarantees that an element in the intersection might make. // If there are more than 2 children, this has already been flattened. if(ast_childcount(ast) > 2) return AST_OK; AST_EXTRACT_CHILDREN(ast, left, right); if((opt->check.frame->constraint == NULL) && (opt->check.frame->iftype_constraint == NULL) && (opt->check.frame->provides == NULL) && !is_compat_type(left, right)) { ast_add(ast, right); ast_add(ast, left); ast_error(opt->check.errors, ast, "intersection types cannot include reference capabilities that are not " "locally compatible"); return AST_ERROR; } flatten_typeexpr_element(ast, left, TK_ISECTTYPE); flatten_typeexpr_element(ast, right, TK_ISECTTYPE); return AST_OK; }
static bool verify_main_create(pass_opt_t* opt, ast_t* ast) { if(ast_id(opt->check.frame->type) != TK_ACTOR) return true; ast_t* type_id = ast_child(opt->check.frame->type); if(strcmp(ast_name(type_id), "Main")) return true; AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error); ast_t* type = ast_parent(ast_parent(ast)); if(strcmp(ast_name(id), "create")) return true; bool ok = true; if(ast_id(ast) != TK_NEW) { ast_error(opt->check.errors, ast, "the create method of the Main actor must be a constructor"); ok = false; } if(ast_id(typeparams) != TK_NONE) { ast_error(opt->check.errors, typeparams, "the create constructor of the Main actor must not take type parameters"); ok = false; } if(ast_childcount(params) != 1) { if(ast_pos(params) == ast_pos(type)) ast_error(opt->check.errors, params, "The Main actor must have a create constructor which takes only a " "single Env parameter"); else ast_error(opt->check.errors, params, "the create constructor of the Main actor must take only 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(opt->check.errors, p_type, "must be of type Env"); ok = false; } } return ok; }
static reachable_type_t* add_tuple(reachable_method_stack_t** s, reachable_types_t* r, uint32_t* next_type_id, ast_t* type) { if(contains_dontcare(type)) return NULL; reachable_type_t* t = reach_type(r, type); if(t != NULL) return t; t = add_reachable_type(r, type); t->type_id = ++(*next_type_id); t->field_count = (uint32_t)ast_childcount(t->ast); t->fields = (reachable_field_t*)calloc(t->field_count, sizeof(reachable_field_t)); size_t index = 0; ast_t* child = ast_child(type); while(child != NULL) { t->fields[index].ast = ast_dup(child); t->fields[index].type = add_type(s, r, next_type_id, child);; index++; child = ast_sibling(child); } return t; }
static bool void_star_param(ast_t* param_type, ast_t* arg_type) { assert(param_type != NULL); assert(arg_type != NULL); if(!is_pointer(param_type)) return false; ast_t* type_args = ast_childidx(param_type, 2); if(ast_childcount(type_args) != 1 || !is_none(ast_child(type_args))) return false; // Parameter type is Pointer[None] // If the argument is Pointer[A], MaybePointer[A] or USize, allow it while(ast_id(arg_type) == TK_ARROW) arg_type = ast_childidx(arg_type, 1); if(is_pointer(arg_type) || is_maybe(arg_type) || is_literal(arg_type, "USize")) return true; return false; }
static void set_method_types(reach_t* r, reach_method_t* m, pass_opt_t* opt) { AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error, body); m->param_count = ast_childcount(params); m->params = (reach_param_t*)ponyint_pool_alloc_size( m->param_count * sizeof(reach_param_t)); ast_t* param = ast_child(params); size_t i = 0; while(param != NULL) { AST_GET_CHILDREN(param, p_id, p_type); m->params[i].type = add_type(r, p_type, opt); if(ast_id(p_type) != TK_NOMINAL && ast_id(p_type) != TK_TYPEPARAMREF) m->params[i].cap = TK_REF; else m->params[i].cap = ast_id(cap_fetch(p_type)); ++i; param = ast_sibling(param); } m->result = add_type(r, result, opt); }
static ast_result_t syntax_compile_error(pass_opt_t* opt, ast_t* ast) { ast_t* parent = ast_parent(ast); assert(ast_id(parent) == TK_SEQ); if(ast_id(ast_parent(parent)) != TK_IFDEF) { ast_error(opt->check.errors, ast, "a compile error must be in an ifdef"); return AST_ERROR; } // AST must be of the form: // (compile_error (seq "Reason")) ast_t* reason_seq = ast_child(ast); if(ast_id(reason_seq) != TK_SEQ || ast_id(ast_child(reason_seq)) != TK_STRING) { ast_error(opt->check.errors, ast, "a compile error must have a string literal reason for the error"); return AST_ERROR; } ast_t* child = ast_child(parent); if((child != ast) || (ast_sibling(child) != NULL) || (ast_childcount(reason_seq) != 1)) { ast_error(opt->check.errors, ast, "a compile error must be the entire ifdef clause"); return AST_ERROR; } return AST_OK; }
static void find_possible_fun_defs(pass_opt_t* opt, ast_t* ast, astlist_t** fun_defs, astlist_t** obj_caps) { switch(ast_id(ast)) { case TK_NOMINAL: { // A lambda type definition must be an interface. ast_t* def = (ast_t*)ast_data(ast); if(ast_id(def) != TK_INTERFACE) return; // The interface must specify just one method in its members. ast_t* members = ast_childidx(def, 4); pony_assert(ast_id(members) == TK_MEMBERS); if(ast_childcount(members) != 1) return; // That one method is the fun def that we're looking for. ast_t* fun_def = ast_child(members); // If the interface type has type parameters, we need to reify. ast_t* typeargs = ast_childidx(ast, 2); ast_t* typeparams = ast_childidx(def, 1); if((ast_id(typeargs) == TK_TYPEARGS) && (ast_id(typeparams) == TK_TYPEPARAMS) ) fun_def = reify_method_def(fun_def, typeparams, typeargs, opt); // Return the object cap and the method definition. *obj_caps = astlist_push(*obj_caps, ast_childidx(ast, 3)); *fun_defs = astlist_push(*fun_defs, fun_def); break; } case TK_ARROW: find_possible_fun_defs(opt, ast_childidx(ast, 1), fun_defs, obj_caps); break; case TK_TYPEPARAMREF: { ast_t* def = (ast_t*)ast_data(ast); pony_assert(ast_id(def) == TK_TYPEPARAM); find_possible_fun_defs(opt, ast_childidx(def, 1), fun_defs, obj_caps); break; } case TK_UNIONTYPE: case TK_ISECTTYPE: { for(ast_t* c = ast_child(ast); c != NULL; c = ast_sibling(c)) find_possible_fun_defs(opt, c, fun_defs, obj_caps); break; } default: break; } }
static bool verify_any_final(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body); if(strcmp(ast_name(id), "_final")) return true; bool ok = true; if((ast_id(opt->check.frame->type) == TK_PRIMITIVE) && (ast_id(ast_childidx(opt->check.frame->type, 1)) != TK_NONE)) { ast_error(opt->check.errors, ast, "a primitive with type parameters cannot have a _final method"); ok = false; } if(ast_id(ast) != TK_FUN) { ast_error(opt->check.errors, ast, "a _final method must be a function"); ok = false; } if(ast_id(cap) != TK_BOX) { ast_error(opt->check.errors, cap, "a _final method must use box as the receiver capability"); ok = false; } if(ast_id(typeparams) != TK_NONE) { ast_error(opt->check.errors, typeparams, "a _final method must not take type parameters"); ok = false; } if(ast_childcount(params) != 0) { ast_error(opt->check.errors, params, "a _final method must take no parameters"); ok = false; } if(!is_none(result)) { ast_error(opt->check.errors, result, "a _final method must return None"); ok = false; } if(ast_id(can_error) != TK_NONE) { ast_error(opt->check.errors, can_error, "a _final method cannot be a partial function"); ok = false; } return ok; }
static void genfun_dwarf(compile_t* c, gentype_t* g, const char *name, ast_t* typeargs, ast_t* fun) { if(!codegen_hassource(c)) return; // Get the function. const char* funname = genname_fun(g->type_name, name, typeargs); LLVMValueRef func = LLVMGetNamedFunction(c->module, funname); assert(func != NULL); // Count the parameters, including the receiver. ast_t* params = ast_childidx(fun, 3); size_t count = ast_childcount(params) + 1; size_t buf_size = (count + 1) * sizeof(const char*); const char** pnames = (const char**)pool_alloc_size(buf_size); count = 0; // Return value type name and receiver type name. pnames[count++] = genname_type(ast_childidx(fun, 4)); pnames[count++] = g->type_name; // Get a type name for each parameter. ast_t* param = ast_child(params); while(param != NULL) { ast_t* ptype = ast_childidx(param, 1); pnames[count++] = genname_type(ptype); param = ast_sibling(param); } // Dwarf the method type dwarf_method(&c->dwarf, fun, name, funname, pnames, count, func); // Dwarf the receiver pointer. LLVMBasicBlockRef entry = LLVMGetEntryBasicBlock(codegen_fun(c)); LLVMValueRef argument = codegen_getlocal(c, stringtab("this")); dwarf_this(&c->dwarf, fun, g->type_name, entry, argument); // Dwarf locals for parameters param = ast_child(params); size_t index = 1; while(param != NULL) { argument = codegen_getlocal(c, ast_name(ast_child(param))); dwarf_parameter(&c->dwarf, param, pnames[index + 1], entry, argument, index); param = ast_sibling(param); index++; } pool_free_size(buf_size, pnames); }
static bool check_finaliser(pass_opt_t* opt, ast_t* ast) { AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body); if(strcmp(ast_name(id), "_final")) return true; bool ok = true; if((ast_id(opt->check.frame->type) == TK_PRIMITIVE) && (ast_id(ast_childidx(opt->check.frame->type, 1)) != TK_NONE)) { ast_error(opt->check.errors, ast, "a primitive with type parameters cannot have a _final"); ok = false; } if(ast_id(ast) != TK_FUN) { ast_error(opt->check.errors, ast, "_final must be a function"); ok = false; } if(ast_id(cap) != TK_BOX) { ast_error(opt->check.errors, cap, "_final must be box"); ok = false; } if(ast_id(typeparams) != TK_NONE) { ast_error(opt->check.errors, typeparams, "_final must not be polymorphic"); ok = false; } if(ast_childcount(params) != 0) { ast_error(opt->check.errors, params, "_final must not have parameters"); ok = false; } if(!is_none(result)) { ast_error(opt->check.errors, result, "_final must return None"); ok = false; } if(ast_id(can_error) != TK_NONE) { ast_error(opt->check.errors, can_error, "_final cannot raise an error"); ok = false; } return ok; }
static void add_as_type(typecheck_t* t, ast_t* type, ast_t* pattern, ast_t* body) { assert(type != NULL); switch(ast_id(type)) { case TK_TUPLETYPE: { BUILD(tuple_pattern, pattern, NODE(TK_SEQ, NODE(TK_TUPLE))); ast_append(pattern, tuple_pattern); ast_t* pattern_child = ast_child(tuple_pattern); BUILD(tuple_body, body, NODE(TK_SEQ, NODE(TK_TUPLE))); ast_t* body_child = ast_child(tuple_body); for(ast_t* p = ast_child(type); p != NULL; p = ast_sibling(p)) add_as_type(t, p, pattern_child, body_child); if(ast_childcount(body_child) == 1) { // Only one child, not actually a tuple ast_t* t = ast_pop(body_child); ast_free(tuple_body); tuple_body = t; } ast_append(body, tuple_body); break; } case TK_DONTCARE: ast_append(pattern, type); break; default: { const char* name = package_hygienic_id(t); ast_t* a_type = alias(type); BUILD(pattern_elem, pattern, NODE(TK_SEQ, NODE(TK_LET, ID(name) TREE(a_type)))); BUILD(body_elem, body, NODE(TK_SEQ, NODE(TK_CONSUME, NODE(TK_BORROWED) NODE(TK_REFERENCE, ID(name))))); ast_append(pattern, pattern_elem); ast_append(body, body_elem); break; } } }
static bool check_tuple(compile_t* c, LLVMValueRef ptr, LLVMValueRef desc, ast_t* pattern_type, LLVMBasicBlockRef next_block) { // First check cardinality. size_t size = ast_childcount(pattern_type); check_cardinality(c, desc, size, next_block); // If we get here, the match expression has the right cardinality. ast_t* pattern_child = ast_child(pattern_type); for(int i = 0; pattern_child != NULL; i++) { // Get the field offset and field descriptor from the tuple descriptor. LLVMValueRef field_info = gendesc_fieldinfo(c, desc, i); LLVMValueRef field_ptr = gendesc_fieldptr(c, ptr, field_info); LLVMValueRef field_desc = gendesc_fielddesc(c, field_info); // If we have a null descriptor, load the object. LLVMBasicBlockRef null_block = codegen_block(c, "null_desc"); LLVMBasicBlockRef nonnull_block = codegen_block(c, "nonnull_desc"); LLVMBasicBlockRef continue_block = codegen_block(c, "merge_desc"); LLVMValueRef test = LLVMBuildIsNull(c->builder, field_desc, ""); LLVMBuildCondBr(c->builder, test, null_block, nonnull_block); // Load the object, load its descriptor, and continue from there. LLVMPositionBuilderAtEnd(c->builder, null_block); LLVMTypeRef ptr_type = LLVMPointerType(c->object_ptr, 0); LLVMValueRef object_ptr = LLVMBuildIntToPtr(c->builder, field_ptr, ptr_type, ""); LLVMValueRef object = LLVMBuildLoad(c->builder, object_ptr, ""); LLVMValueRef object_desc = gendesc_fetch(c, object); object_ptr = gendesc_ptr_to_fields(c, object, object_desc); if(!check_type(c, object_ptr, object_desc, pattern_child, next_block)) return false; LLVMBuildBr(c->builder, continue_block); // Continue with the pointer and descriptor. LLVMPositionBuilderAtEnd(c->builder, nonnull_block); if(!check_type(c, field_ptr, field_desc, pattern_child, next_block)) return false; LLVMBuildBr(c->builder, continue_block); // Merge the two branches. LLVMPositionBuilderAtEnd(c->builder, continue_block); pattern_child = ast_sibling(pattern_child); } return true; }
static bool extend_positional_args(ast_t* params, ast_t* positional) { // Fill out the positional args to be as long as the param list. size_t param_len = ast_childcount(params); size_t arg_len = ast_childcount(positional); if(arg_len > param_len) { ast_error(positional, "too many arguments"); return false; } while(arg_len < param_len) { ast_setid(positional, TK_POSITIONALARGS); ast_append(positional, ast_from(positional, TK_NONE)); arg_len++; } return true; }
static bool is_tuple_sub_tuple(ast_t* sub, ast_t* super, errorframe_t* errors) { // T1 <: T3 // T2 <: T4 // --- // (T1, T2) <: (T3, T4) if(ast_childcount(sub) != ast_childcount(super)) { if(errors != NULL) { ast_error_frame(errors, sub, "%s is not a subtype of %s: they have a different number of elements", ast_print_type(sub), ast_print_type(super)); } return false; } ast_t* sub_child = ast_child(sub); ast_t* super_child = ast_child(super); bool ret = true; while(sub_child != NULL) { if(!is_subtype(sub_child, super_child, errors)) ret = false; sub_child = ast_sibling(sub_child); super_child = ast_sibling(super_child); } if(!ret && errors != NULL) { ast_error_frame(errors, sub, "%s is not a pairwise subtype of %s", ast_print_type(sub), ast_print_type(super)); } return ret; }
static void setup_tuple_fields(gentype_t* g) { g->field_count = (int)ast_childcount(g->ast); g->fields = (ast_t**)calloc(g->field_count, sizeof(ast_t*)); ast_t* child = ast_child(g->ast); size_t index = 0; while(child != NULL) { g->fields[index++] = child; child = ast_sibling(child); } }
static LLVMTypeRef get_signature(compile_t* c, gentype_t* g, ast_t* fun) { // Get a type for the result. ast_t* rtype = ast_childidx(fun, 4); gentype_t rtype_g; if(!gentype(c, rtype, &rtype_g)) { ast_error(rtype, "couldn't generate result type"); return NULL; } // Count the parameters, including the receiver. ast_t* params = ast_childidx(fun, 3); size_t count = ast_childcount(params) + 1; size_t buf_size = count *sizeof(LLVMTypeRef); LLVMTypeRef* tparams = (LLVMTypeRef*)pool_alloc_size(buf_size); count = 0; // Get a type for the receiver. tparams[count++] = g->use_type; // Get a type for each parameter. ast_t* param = ast_child(params); while(param != NULL) { ast_t* ptype = ast_childidx(param, 1); gentype_t ptype_g; if(!gentype(c, ptype, &ptype_g)) { ast_error(ptype, "couldn't generate parameter type"); pool_free_size(buf_size, tparams); return NULL; } tparams[count++] = ptype_g.use_type; param = ast_sibling(param); } LLVMTypeRef result = rtype_g.use_type; // Generate the function type. LLVMTypeRef r = LLVMFunctionType(result, tparams, (int)count, false); pool_free_size(buf_size, tparams); return r; }
static ast_result_t flatten_union(pass_opt_t* opt, ast_t* ast) { (void)opt; // Flatten unions without testing subtyping. This will be tested after the // traits pass, when we have full subtyping information. // If there are more than 2 children, this has already been flattened. if(ast_childcount(ast) > 2) return AST_OK; AST_EXTRACT_CHILDREN(ast, left, right); flatten_typeexpr_element(ast, left, TK_UNIONTYPE); flatten_typeexpr_element(ast, right, TK_UNIONTYPE); 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; }
static bool check_finaliser(ast_t* ast) { AST_GET_CHILDREN(ast, cap, id, typeparams, params, result, can_error, body); if(strcmp(ast_name(id), "_final")) return true; bool ok = true; if(ast_id(ast) != TK_FUN) { ast_error(ast, "_final must be a function"); ok = false; } if(ast_id(cap) != TK_BOX) { ast_error(cap, "_final must be box"); ok = false; } if(ast_id(typeparams) != TK_NONE) { ast_error(typeparams, "_final must not be polymorphic"); ok = false; } if(ast_childcount(params) != 0) { ast_error(params, "_final must not have parameters"); ok = false; } if(!is_none(result)) { ast_error(result, "_final must return None"); ok = false; } if(ast_id(can_error) != TK_NONE) { ast_error(can_error, "_final cannot raise an error"); ok = false; } return ok; }
static void make_global_descriptor(compile_t* c, gentype_t* g) { // Fetch or create a descriptor type. if(g->underlying == TK_TUPLETYPE) g->field_count = (int)ast_childcount(g->ast); // Check for an existing descriptor. g->desc_type = gendesc_type(c, g); g->desc = LLVMGetNamedGlobal(c->module, g->desc_name); if(g->desc != NULL) return; g->desc = LLVMAddGlobal(c->module, g->desc_type, g->desc_name); LLVMSetGlobalConstant(g->desc, true); LLVMSetLinkage(g->desc, LLVMInternalLinkage); }
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 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; }