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 print_types(compile_t* c, FILE* fp, printbuf_t* buf) { size_t i = HASHMAP_BEGIN; reachable_type_t* t; while((t = reachable_types_next(c->reachable, &i)) != NULL) { // Print the docstring if we have one. ast_t* def = (ast_t*)ast_data(t->ast); ast_t* docstring = ast_childidx(def, 6); if(ast_id(docstring) == TK_STRING) fprintf(fp, "/*\n%s*/\n", ast_name(docstring)); if(!is_pointer(t->ast) && !is_maybe(t->ast) && !is_machine_word(t->ast)) { // Forward declare an opaque type. fprintf(fp, "typedef struct %s %s;\n\n", t->name, t->name); // Function signature for the allocator. printbuf(buf, "/* Allocate a %s without initialising it. */\n%s* %s_Alloc();\n\n", t->name, t->name, t->name ); } print_methods(c, t, buf); } }
static int print_pointer_type(compile_t* c, printbuf_t* buf, ast_t* type) { ast_t* typeargs = ast_childidx(type, 2); ast_t* elem = ast_child(typeargs); if(is_pointer(elem) || is_maybe(elem)) return print_pointer_type(c, buf, elem) + 1; print_base_type(c, buf, elem); return 1; }
static trace_t trace_type_nominal(ast_t* type) { switch(ast_id((ast_t*)ast_data(type))) { case TK_INTERFACE: case TK_TRAIT: switch(cap_single(type)) { case TK_VAL: return TRACE_VAL_UNKNOWN; case TK_TAG: return TRACE_TAG_UNKNOWN; default: {} } return TRACE_MUT_UNKNOWN; case TK_PRIMITIVE: { if(is_machine_word(type)) return TRACE_MACHINE_WORD; return TRACE_PRIMITIVE; } case TK_STRUCT: case TK_CLASS: if(is_maybe(type)) return TRACE_MAYBE; switch(cap_single(type)) { case TK_VAL: return TRACE_VAL_KNOWN; case TK_TAG: return TRACE_TAG_KNOWN; default: {} } return TRACE_MUT_KNOWN; case TK_ACTOR: return TRACE_TAG_KNOWN; default: {} } pony_assert(0); return TRACE_NONE; }
static void print_type_name(compile_t* c, printbuf_t* buf, ast_t* type) { if(is_pointer(type) || is_maybe(type)) { int depth = print_pointer_type(c, buf, type); for(int i = 0; i < depth; i++) printbuf(buf, "*"); } else { print_base_type(c, buf, type); } }
static trace_t trace_type_nominal(ast_t* type) { switch(ast_id((ast_t*)ast_data(type))) { case TK_INTERFACE: case TK_TRAIT: switch(cap_single(type)) { case TK_VAL: return TRACE_UNKNOWN_VAL; case TK_TAG: return TRACE_TAG_OR_ACTOR; default: {} } return TRACE_UNKNOWN; case TK_PRIMITIVE: return TRACE_PRIMITIVE; case TK_STRUCT: case TK_CLASS: if(is_maybe(type)) return TRACE_MAYBE; switch(cap_single(type)) { case TK_VAL: return TRACE_KNOWN_VAL; case TK_TAG: return TRACE_TAG; default: {} } return TRACE_KNOWN; case TK_ACTOR: return TRACE_ACTOR; default: {} } assert(0); return TRACE_NONE; }
static bool genfun_allocator(compile_t* c, reachable_type_t* t) { switch(t->underlying) { case TK_PRIMITIVE: case TK_STRUCT: case TK_CLASS: case TK_ACTOR: break; default: return true; } // No allocator for machine word types or pointers. if((t->primitive != NULL) || is_pointer(t->ast) || is_maybe(t->ast)) return true; const char* funname = genname_fun(t->name, "Alloc", NULL); LLVMTypeRef ftype = LLVMFunctionType(t->use_type, NULL, 0, false); LLVMValueRef fun = codegen_addfun(c, funname, ftype); codegen_startfun(c, fun, NULL, NULL); LLVMValueRef result; switch(t->underlying) { case TK_PRIMITIVE: case TK_STRUCT: case TK_CLASS: // Allocate the object or return the global instance. result = gencall_alloc(c, t); break; case TK_ACTOR: // Allocate the actor. result = gencall_create(c, t); break; default: assert(0); return false; } LLVMBuildRet(c->builder, result); codegen_finishfun(c); return true; }
static void setup_dwarf(dwarf_t* dwarf, dwarf_meta_t* meta, gentype_t* g, bool opaque, bool field) { memset(meta, 0, sizeof(dwarf_meta_t)); ast_t* ast = g->ast; LLVMTypeRef type = g->primitive; if(is_machine_word(ast)) { if(is_float(ast)) meta->flags |= DWARF_FLOAT; else if(is_signed(dwarf->opt, ast)) meta->flags |= DWARF_SIGNED; else if(is_bool(ast)) meta->flags |= DWARF_BOOLEAN; } else if(is_pointer(ast) || is_maybe(ast) || !is_concrete(ast) || (is_constructable(ast) && field)) { type = g->use_type; } else if(is_constructable(ast)) { type = g->structure; } bool defined_type = g->underlying != TK_TUPLETYPE && g->underlying != TK_UNIONTYPE && g->underlying != TK_ISECTTYPE; source_t* source; if(defined_type) ast = (ast_t*)ast_data(ast); source = ast_source(ast); meta->file = source->file; meta->name = g->type_name; meta->line = ast_line(ast); meta->pos = ast_pos(ast); if(!opaque) { meta->size = LLVMABISizeOfType(dwarf->target_data, type) << 3; meta->align = LLVMABIAlignmentOfType(dwarf->target_data, type) << 3; } }
LLVMValueRef gencall_alloc(compile_t* c, reach_type_t* t) { // Do nothing for primitives. if(t->primitive != NULL) return NULL; // Do nothing for Pointer and Maybe. if(is_pointer(t->ast) || is_maybe(t->ast)) return NULL; // Use the global instance if we have one. if(t->instance != NULL) return t->instance; if(t->underlying == TK_ACTOR) return gencall_create(c, t); return gencall_allocstruct(c, t); }
static bool call_needs_receiver(ast_t* postfix, reach_type_t* t) { switch(ast_id(postfix)) { case TK_NEWREF: case TK_NEWBEREF: break; default: return true; } // No receiver if a new primitive. if(t->primitive != NULL) return false; // No receiver if a new Pointer or Maybe. if(is_pointer(t->ast) || is_maybe(t->ast)) return false; return true; }
static bool call_needs_receiver(ast_t* postfix, reach_type_t* t) { switch(ast_id(postfix)) { case TK_NEWREF: case TK_NEWBEREF: // No receiver if a new primitive. if(((compile_type_t*)t->c_type)->primitive != NULL) return false; // No receiver if a new Pointer or Maybe. if(is_pointer(t->ast) || is_maybe(t->ast)) return false; return true; // Always generate the receiver, even for bare function calls. This ensures // that side-effects always happen. default: return true; } }
bool expr_nominal(pass_opt_t* opt, ast_t** astp) { // Resolve type aliases and typeparam references. if(!names_nominal(opt, *astp, astp, true)) return false; ast_t* ast = *astp; switch(ast_id(ast)) { case TK_TYPEPARAMREF: return flatten_typeparamref(opt, 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 or an Array. These // builtin types have no contraint on their type parameter, and it is safe // to bind a struct as a type argument (which is not safe on any user defined // type, as that type might then be used for pattern matching). if(is_pointer(ast) || is_literal(ast, "Array")) return true; ast_t* typeparams = ast_childidx(def, 1); ast_t* typeargs = ast_childidx(ast, 2); if(!reify_defaults(typeparams, typeargs, true, opt)) return false; if(is_maybe(ast)) { // MaybePointer[A] must be bound to a struct. assert(ast_childcount(typeargs) == 1); ast_t* typeparam = ast_child(typeparams); ast_t* typearg = ast_child(typeargs); bool ok = false; switch(ast_id(typearg)) { case TK_NOMINAL: { ast_t* def = (ast_t*)ast_data(typearg); ok = ast_id(def) == TK_STRUCT; break; } case TK_TYPEPARAMREF: { ast_t* def = (ast_t*)ast_data(typearg); ok = def == typeparam; break; } default: {} } if(!ok) { ast_error(opt->check.errors, ast, "%s is not allowed: " "the type argument to MaybePointer must be a struct", ast_print_type(ast)); return false; } return true; } return check_constraints(typeargs, typeparams, typeargs, true, opt); }
bool gentrace(compile_t* c, LLVMValueRef ctx, LLVMValueRef value, ast_t* type) { bool tag = trace_as_tag(c, value, type); switch(ast_id(type)) { case TK_UNIONTYPE: case TK_ISECTTYPE: { if(tag) trace_tag_or_actor(c, ctx, value); else trace_unknown(c, ctx, value); return true; } case TK_TUPLETYPE: return trace_tuple(c, ctx, value, type); case TK_NOMINAL: { switch(ast_id((ast_t*)ast_data(type))) { case TK_INTERFACE: case TK_TRAIT: if(tag) trace_tag_or_actor(c, ctx, value); else trace_unknown(c, ctx, value); return true; case TK_PRIMITIVE: // Do nothing. return false; case TK_STRUCT: case TK_CLASS: if(tag) { if(is_maybe(type)) trace_maybe(c, ctx, value, type, true); else trace_tag(c, ctx, value); return true; } if(is_maybe(type)) { trace_maybe(c, ctx, value, type, false); return true; } return trace_known(c, ctx, value, type); case TK_ACTOR: trace_actor(c, ctx, value); return true; default: {} } break; } default: {} } assert(0); return false; }