bool is_concrete(ast_t* type) { switch(ast_id(type)) { case TK_UNIONTYPE: case TK_TUPLETYPE: return false; case TK_ISECTTYPE: { ast_t* child = ast_child(type); while(child != NULL) { if(is_concrete(child)) return true; child = ast_sibling(child); } return false; } case TK_NOMINAL: { ast_t* def = (ast_t*)ast_data(type); switch(ast_id(def)) { case TK_INTERFACE: case TK_TRAIT: return false; case TK_PRIMITIVE: case TK_CLASS: case TK_ACTOR: return true; default: {} } break; } case TK_TYPEPARAMREF: { ast_t* def = (ast_t*)ast_data(type); ast_t* constraint = ast_childidx(def, 1); return is_constructable(constraint); } case TK_ARROW: return is_concrete(ast_childidx(type, 1)); default: {} } assert(0); return false; }
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; } }
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; }
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; }
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(is_bare(typearg)) { if(report_errors) { ast_error(opt->check.errors, typearg, "a bare type cannot be used as a type argument"); } return false; } switch(ast_id(typearg)) { case TK_NOMINAL: { ast_t* def = (ast_t*)ast_data(typearg); if(ast_id(def) == TK_STRUCT) { if(report_errors) { ast_error(opt->check.errors, typearg, "a struct cannot be used as a type argument"); } return false; } break; } case TK_TYPEPARAMREF: { ast_t* def = (ast_t*)ast_data(typearg); if(def == typeparam) { typeparam = ast_sibling(typeparam); typearg = ast_sibling(typearg); continue; } break; } default: {} } // Reify the constraint. ast_t* constraint = ast_childidx(typeparam, 1); ast_t* r_constraint = reify(constraint, typeparams, typeargs, opt, true); // A bound type must be a subtype of the constraint. errorframe_t info = NULL; errorframe_t* infop = (report_errors ? &info : NULL); if(!is_subtype_constraint(typearg, r_constraint, infop, opt)) { 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, opt->check.errors); } 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); } pony_assert(typeparam == NULL); pony_assert(typearg == NULL); return true; }
bool is_constructable(ast_t* type) { if(type == NULL) return false; switch(ast_id(type)) { case TK_UNIONTYPE: case TK_TUPLETYPE: return false; case TK_ISECTTYPE: { ast_t* child = ast_child(type); while(child != NULL) { if(is_constructable(child)) return true; child = ast_sibling(child); } return false; } case TK_NOMINAL: { ast_t* def = (ast_t*)ast_data(type); switch(ast_id(def)) { case TK_INTERFACE: case TK_TRAIT: { ast_t* members = ast_childidx(def, 4); ast_t* member = ast_child(members); while(member != NULL) { if(ast_id(member) == TK_NEW) return true; member = ast_sibling(member); } return false; } case TK_PRIMITIVE: case TK_STRUCT: case TK_CLASS: case TK_ACTOR: return true; default: {} } break; } case TK_TYPEPARAMREF: return is_constructable(typeparam_constraint(type)); case TK_ARROW: return is_constructable(ast_childidx(type, 1)); default: {} } assert(0); return false; }
bool check_constraints(ast_t* orig, ast_t* typeparams, ast_t* typeargs, bool report_errors) { // Reify the type parameters with the typeargs. ast_t* r_typeparams = reify(orig, typeparams, typeparams, typeargs); if(r_typeparams == NULL) return false; ast_t* r_typeparam = ast_child(r_typeparams); ast_t* typeparam = ast_child(typeparams); ast_t* typearg = ast_child(typeargs); while(r_typeparam != NULL) { // Use the reified constraint. ast_t* r_constraint = ast_childidx(r_typeparam, 1); r_constraint = bind_type(r_constraint); // A bound type must be a subtype of the constraint. if(!is_subtype(typearg, r_constraint)) { if(report_errors) { ast_error(orig, "type argument is outside its constraint"); ast_error(typearg, "argument: %s", ast_print_type(typearg)); ast_error(typeparam, "constraint: %s", ast_print_type(r_constraint)); } ast_free_unattached(r_typeparams); ast_free_unattached(r_constraint); return false; } ast_free_unattached(r_constraint); // A constructable constraint can only be fulfilled by a concrete typearg. ast_t* constraint = ast_childidx(typeparam, 1); 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)); } ast_free_unattached(r_typeparams); return false; } r_typeparam = ast_sibling(r_typeparam); typeparam = ast_sibling(typeparam); typearg = ast_sibling(typearg); } assert(r_typeparam == NULL); assert(typearg == NULL); ast_free_unattached(r_typeparams); return true; }