diff --git a/src/check_decl.cpp b/src/check_decl.cpp index 7dda04553..f63aecf67 100644 --- a/src/check_decl.cpp +++ b/src/check_decl.cpp @@ -1032,8 +1032,13 @@ void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNod Entity *e = decl->deps.entries[i].ptr; ptr_set_add(&decl->parent->deps, e); } + for_array(i, decl->type_info_deps.entries) { + Type *t = decl->type_info_deps.entries[i].ptr; + ptr_set_add(&decl->parent->type_info_deps, t); + } } } + diff --git a/src/check_expr.cpp b/src/check_expr.cpp index 8bdb23658..c4a1e7a43 100644 --- a/src/check_expr.cpp +++ b/src/check_expr.cpp @@ -329,7 +329,7 @@ bool find_or_generate_polymorphic_procedure(Checker *c, Entity *base_entity, Typ u64 tags = base_entity->Procedure.tags; AstNode *ident = clone_ast_node(a, base_entity->identifier); Token token = ident->Ident.token; - DeclInfo *d = make_declaration_info(c->allocator, scope, old_decl->parent); + DeclInfo *d = make_decl_info(c->allocator, scope, old_decl->parent); d->gen_proc_type = final_proc_type; d->type_expr = pl->type; d->proc_lit = proc_lit; @@ -4327,6 +4327,9 @@ CALL_ARGUMENT_CHECKER(check_call_arguments_internal) { err = CallArgumentError_WrongTypes; } score += s; + if (is_type_any(elem)) { + add_type_info_type(c, o.type); + } } } } @@ -5299,7 +5302,7 @@ ExprKind check_expr_base_internal(Checker *c, Operand *o, AstNode *node, Type *t Type *type = alloc_type(Type_Proc); check_open_scope(c, pl->type); { - decl = make_declaration_info(c->allocator, c->context.scope, c->context.decl); + decl = make_decl_info(c->allocator, c->context.scope, c->context.decl); decl->proc_lit = node; c->context.decl = decl; diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 13b95ddad..72c6f5487 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -871,6 +871,7 @@ void check_type_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) { check_expr(c, &x, rhs); check_assignment(c, &x, nullptr, str_lit("type switch expression")); + add_type_info_type(c, x.type); TypeSwitchKind switch_kind = check_valid_type_switch_type(x.type); if (switch_kind == TypeSwitch_Invalid) { @@ -962,8 +963,10 @@ void check_type_switch_stmt(Checker *c, AstNode *node, u32 mod_flags) { continue; } case_type = y.type; + add_type_info_type(c, y.type); } else if (switch_kind == TypeSwitch_Any) { case_type = y.type; + add_type_info_type(c, y.type); } else { GB_PANIC("Unknown type to type switch statement"); } diff --git a/src/checker.cpp b/src/checker.cpp index da6fe5b9a..6d035760c 100644 --- a/src/checker.cpp +++ b/src/checker.cpp @@ -173,16 +173,17 @@ GB_COMPARE_PROC(ast_node_cmp) { -void init_declaration_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { +void init_decl_info(DeclInfo *d, Scope *scope, DeclInfo *parent) { d->parent = parent; d->scope = scope; - ptr_set_init(&d->deps, heap_allocator()); - array_init (&d->labels, heap_allocator()); + ptr_set_init(&d->deps, heap_allocator()); + ptr_set_init(&d->type_info_deps, heap_allocator()); + array_init (&d->labels, heap_allocator()); } -DeclInfo *make_declaration_info(gbAllocator a, Scope *scope, DeclInfo *parent) { +DeclInfo *make_decl_info(gbAllocator a, Scope *scope, DeclInfo *parent) { DeclInfo *d = gb_alloc_item(a, DeclInfo); - init_declaration_info(d, scope, parent); + init_decl_info(d, scope, parent); return d; } @@ -483,12 +484,20 @@ void check_scope_usage(Checker *c, Scope *scope) { void add_dependency(DeclInfo *d, Entity *e) { ptr_set_add(&d->deps, e); } +void add_type_info_dependency(DeclInfo *d, Type *type) { + if (d == nullptr) { + GB_ASSERT(type == t_invalid); + return; + } + ptr_set_add(&d->type_info_deps, type); +} void add_preload_dependency(Checker *c, char *name) { String n = make_string_c(name); Entity *e = scope_lookup_entity(c->global_scope, n); GB_ASSERT(e != nullptr); ptr_set_add(&c->context.decl->deps, e); + // add_type_info_type(c, e->type); } void add_declaration_dependency(Checker *c, Entity *e) { @@ -959,8 +968,10 @@ void add_type_info_type(Checker *c, Type *t) { return; } - if (map_get(&c->info.type_info_map, hash_type(t)) != nullptr) { + auto found = map_get(&c->info.type_info_map, hash_type(t)); + if (found != nullptr) { // Types have already been added + add_type_info_dependency(c->context.decl, t); return; } @@ -986,6 +997,7 @@ void add_type_info_type(Checker *c, Type *t) { if (prev) { // NOTE(bill): If a previous one exists already, no need to continue + add_type_info_dependency(c->context.decl, t); return; } @@ -1133,43 +1145,175 @@ void add_curr_ast_file(Checker *c, AstFile *file) { } } +void add_min_dep_type_info(Checker *c, Type *t) { + if (t == nullptr) { + return; + } + t = default_type(t); + if (is_type_bit_field_value(t)) { + t = default_bit_field_value_type(t); + } + if (is_type_untyped(t)) { + return; // Could be nil + } + if (is_type_polymorphic(base_type(t))) { + return; + } -void add_dependency_to_map(PtrSet *map, CheckerInfo *info, Entity *entity) { + auto *set = &c->info.minimum_dependency_type_info_set; + + isize ti_index = type_info_index(&c->info, t); + if (ptr_set_exists(set, ti_index)) { + // Type Already exists + return; + } + ptr_set_add(set, ti_index); + + // Add nested types + if (t->kind == Type_Named) { + // NOTE(bill): Just in case + add_min_dep_type_info(c, t->Named.base); + return; + } + + Type *bt = base_type(t); + add_min_dep_type_info(c, bt); + + switch (bt->kind) { + case Type_Basic: + switch (bt->Basic.kind) { + case Basic_string: + add_min_dep_type_info(c, t_u8_ptr); + add_min_dep_type_info(c, t_int); + break; + case Basic_any: + add_min_dep_type_info(c, t_type_info_ptr); + add_min_dep_type_info(c, t_rawptr); + break; + + case Basic_complex64: + add_min_dep_type_info(c, t_type_info_float); + add_min_dep_type_info(c, t_f32); + break; + case Basic_complex128: + add_min_dep_type_info(c, t_type_info_float); + add_min_dep_type_info(c, t_f64); + break; + } + break; + + case Type_Pointer: + add_min_dep_type_info(c, bt->Pointer.elem); + break; + + case Type_Array: + add_min_dep_type_info(c, bt->Array.elem); + add_min_dep_type_info(c, alloc_type_pointer(bt->Array.elem)); + add_min_dep_type_info(c, t_int); + break; + case Type_DynamicArray: + add_min_dep_type_info(c, bt->DynamicArray.elem); + add_min_dep_type_info(c, alloc_type_pointer(bt->DynamicArray.elem)); + add_min_dep_type_info(c, t_int); + add_min_dep_type_info(c, t_allocator); + break; + case Type_Slice: + add_min_dep_type_info(c, bt->Slice.elem); + add_min_dep_type_info(c, alloc_type_pointer(bt->Slice.elem)); + add_min_dep_type_info(c, t_int); + break; + + case Type_Enum: + add_min_dep_type_info(c, bt->Enum.base_type); + break; + + case Type_Union: + add_min_dep_type_info(c, t_int); + add_min_dep_type_info(c, t_type_info_ptr); + for_array(i, bt->Union.variants) { + add_min_dep_type_info(c, bt->Union.variants[i]); + } + break; + + case Type_Struct: + if (bt->Struct.scope != nullptr) { + for_array(i, bt->Struct.scope->elements.entries) { + Entity *e = bt->Struct.scope->elements.entries[i].value; + add_min_dep_type_info(c, e->type); + } + } + for_array(i, bt->Struct.fields) { + Entity *f = bt->Struct.fields[i]; + add_min_dep_type_info(c, f->type); + } + break; + + case Type_Map: + init_map_internal_types(bt); + add_min_dep_type_info(c, bt->Map.key); + add_min_dep_type_info(c, bt->Map.value); + add_min_dep_type_info(c, bt->Map.generated_struct_type); + break; + + case Type_Tuple: + for_array(i, bt->Tuple.variables) { + Entity *var = bt->Tuple.variables[i]; + add_min_dep_type_info(c, var->type); + } + break; + + case Type_Proc: + add_min_dep_type_info(c, bt->Proc.params); + add_min_dep_type_info(c, bt->Proc.results); + break; + } +} + + +void add_dependency_to_set(Checker *c, Entity *entity) { if (entity == nullptr) { return; } + CheckerInfo *info = &c->info; + auto *set = &info->minimum_dependency_set; + String name = entity->token.string; if (entity->type != nullptr && is_type_polymorphic(entity->type)) { - DeclInfo *decl = decl_info_of_entity(info, entity); + DeclInfo *decl = decl_info_of_entity(&c->info, entity); if (decl != nullptr && decl->gen_proc_type == nullptr) { return; } } - if (ptr_set_exists(map, entity)) { + if (ptr_set_exists(set, entity)) { return; } - ptr_set_add(map, entity); + ptr_set_add(set, entity); DeclInfo *decl = decl_info_of_entity(info, entity); if (decl == nullptr) { return; } + for_array(i, decl->type_info_deps.entries) { + Type *type = decl->type_info_deps.entries[i].ptr; + add_min_dep_type_info(c, type); + } + for_array(i, decl->deps.entries) { Entity *e = decl->deps.entries[i].ptr; - add_dependency_to_map(map, info, e); + add_dependency_to_set(c, e); if (e->kind == Entity_Procedure && e->Procedure.is_foreign) { Entity *fl = e->Procedure.foreign_library; if (fl != nullptr) { GB_ASSERT_MSG(fl->kind == Entity_LibraryName && fl->LibraryName.used, "%.*s", LIT(name)); - add_dependency_to_map(map, info, fl); + add_dependency_to_set(c, fl); } } if (e->kind == Entity_Variable && e->Variable.is_foreign) { @@ -1178,16 +1322,15 @@ void add_dependency_to_map(PtrSet *map, CheckerInfo *info, Entity *ent GB_ASSERT_MSG(fl->kind == Entity_LibraryName && fl->LibraryName.used, "%.*s", LIT(name)); - add_dependency_to_map(map, info, fl); + add_dependency_to_set(c, fl); } } } } -PtrSet generate_minimum_dependency_set(Checker *c, Entity *start) { - CheckerInfo *info = &c->info; - PtrSet map = {}; // Key: Entity * - ptr_set_init(&map, heap_allocator()); +void generate_minimum_dependency_set(Checker *c, Entity *start) { + ptr_set_init(&c->info.minimum_dependency_set, heap_allocator()); + ptr_set_init(&c->info.minimum_dependency_type_info_set, heap_allocator()); String required_entities[] = { str_lit("__mem_zero"), @@ -1204,7 +1347,7 @@ PtrSet generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("Context"), }; for (isize i = 0; i < gb_count_of(required_entities); i++) { - add_dependency_to_map(&map, info, scope_lookup_entity(c->global_scope, required_entities[i])); + add_dependency_to_set(c, scope_lookup_entity(c->global_scope, required_entities[i])); } if (!build_context.no_bounds_check) { @@ -1214,27 +1357,25 @@ PtrSet generate_minimum_dependency_set(Checker *c, Entity *start) { str_lit("__dynamic_array_expr_error"), }; for (isize i = 0; i < gb_count_of(bounds_check_entities); i++) { - add_dependency_to_map(&map, info, scope_lookup_entity(c->global_scope, bounds_check_entities[i])); + add_dependency_to_set(c, scope_lookup_entity(c->global_scope, bounds_check_entities[i])); } } - for_array(i, info->definitions) { - Entity *e = info->definitions[i]; + for_array(i, c->info.definitions) { + Entity *e = c->info.definitions[i]; // if (e->scope->is_global && !is_type_poly_proc(e->type)) { // TODO(bill): is the check enough? if (e->scope == universal_scope) { // TODO(bill): is the check enough? if (e->type == nullptr || !is_type_poly_proc(e->type)) { - add_dependency_to_map(&map, info, e); + add_dependency_to_set(c, e); } } else if (e->kind == Entity_Procedure && e->Procedure.is_export) { - add_dependency_to_map(&map, info, e); + add_dependency_to_set(c, e); } else if (e->kind == Entity_Variable && e->Procedure.is_export) { - add_dependency_to_map(&map, info, e); + add_dependency_to_set(c, e); } } - add_dependency_to_map(&map, info, start); - - return map; + add_dependency_to_set(c, start); } bool is_entity_a_dependency(Entity *e) { @@ -1794,7 +1935,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) { Entity **entities = gb_alloc_array(c->allocator, Entity *, entity_cap); DeclInfo *di = nullptr; if (vd->values.count > 0) { - di = make_declaration_info(heap_allocator(), c->context.scope, c->context.decl); + di = make_decl_info(heap_allocator(), c->context.scope, c->context.decl); di->entities = entities; di->type_expr = vd->type; di->init_expr = vd->values[0]; @@ -1838,7 +1979,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) { DeclInfo *d = di; if (d == nullptr || i > 0) { AstNode *init_expr = value; - d = make_declaration_info(heap_allocator(), e->scope, c->context.decl); + d = make_decl_info(heap_allocator(), e->scope, c->context.decl); d->type_expr = vd->type; d->init_expr = init_expr; } @@ -1869,7 +2010,7 @@ void check_collect_value_decl(Checker *c, AstNode *decl) { Token token = name->Ident.token; AstNode *fl = c->context.foreign_context.curr_library; - DeclInfo *d = make_declaration_info(c->allocator, c->context.scope, c->context.decl); + DeclInfo *d = make_decl_info(c->allocator, c->context.scope, c->context.decl); Entity *e = nullptr; d->attributes = vd->attributes; @@ -3088,7 +3229,7 @@ void check_parsed_files(Checker *c) { for_array(i, c->parser->files) { AstFile *f = c->parser->files[i]; Scope *scope = create_scope_from_file(c, f); - f->decl_info = make_declaration_info(c->allocator, f->scope, c->context.decl); + f->decl_info = make_decl_info(c->allocator, f->scope, c->context.decl); HashKey key = hash_string(f->tokenizer.fullpath); map_set(&c->file_scopes, key, scope); map_set(&c->info.files, key, f); @@ -3151,7 +3292,7 @@ void check_parsed_files(Checker *c) { } TIME_SECTION("generate minimum dependency set"); - c->info.minimum_dependency_set = generate_minimum_dependency_set(c, c->info.entry_point); + generate_minimum_dependency_set(c, c->info.entry_point); TIME_SECTION("calculate global init order"); diff --git a/src/checker.hpp b/src/checker.hpp index ff930667d..b2ea3a921 100644 --- a/src/checker.hpp +++ b/src/checker.hpp @@ -186,6 +186,7 @@ struct DeclInfo { Type * gen_proc_type; // Precalculated PtrSet deps; + PtrSet type_info_deps; Array labels; }; @@ -303,9 +304,11 @@ struct CheckerInfo { Array type_info_types; Map type_info_map; // Key: Type * + Scope * init_scope; Entity * entry_point; PtrSet minimum_dependency_set; + PtrSet minimum_dependency_type_info_set; }; struct Checker { @@ -374,13 +377,13 @@ void add_type_and_value (CheckerInfo *i, AstNode *expression, Addressi void add_entity_use (Checker *c, AstNode *identifier, Entity *entity); void add_implicit_entity (Checker *c, AstNode *node, Entity *e); void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclInfo *d); +void add_type_info_type (Checker *c, Type *t); void check_add_import_decl(Checker *c, AstNodeImportDecl *id); void check_add_export_decl(Checker *c, AstNodeExportDecl *ed); void check_add_foreign_import_decl(Checker *c, AstNode *decl); - bool check_arity_match(Checker *c, AstNodeValueDecl *vd, bool is_global = false); void check_collect_entities(Checker *c, Array nodes); void check_collect_entities_from_when_stmt(Checker *c, AstNodeWhenStmt *ws); diff --git a/src/ir.cpp b/src/ir.cpp index 18e7eed6a..f4f795e6d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3586,13 +3586,41 @@ gb_global i32 ir_global_type_info_member_names_index = 0; gb_global i32 ir_global_type_info_member_offsets_index = 0; gb_global i32 ir_global_type_info_member_usings_index = 0; +#if 1 +isize ir_type_info_count(CheckerInfo *info) { + return info->minimum_dependency_type_info_set.entries.count+1; +} + +isize ir_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) { + isize index = type_info_index(info, type); + auto *set = &info->minimum_dependency_type_info_set; + for_array(i, set->entries) { + if (set->entries[i].ptr == index) { + return i+1; + } + } + if (err_on_not_found) { + GB_PANIC("NOT FOUND ir_type_info_index %s", type_to_string(type)); + } + return -1; +} +#else +isize ir_type_info_count(CheckerInfo *info) { + return info->type_info_types.count; +} + +isize ir_type_info_index(CheckerInfo *info, Type *type) { + isize index = type_info_index(info, type); + return index; +} +#endif irValue *ir_type_info(irProcedure *proc, Type *type) { CheckerInfo *info = proc->module->info; type = default_type(type); - i32 entry_index = cast(i32)type_info_index(info, type); + i32 entry_index = cast(i32)ir_type_info_index(info, type); GB_ASSERT(entry_index >= 0); // gb_printf_err("%d %s\n", entry_index, type_to_string(type)); @@ -4173,7 +4201,6 @@ irValue *ir_build_builtin_proc(irProcedure *proc, AstNode *expr, TypeAndValue tv case BuiltinProc_type_info_of: { Type *t = default_type(type_of_expr(proc->module->info, ce->args[0])); return ir_type_info(proc, t); - break; } case BuiltinProc_len: { @@ -4806,7 +4833,7 @@ irValue *ir_build_expr_internal(irProcedure *proc, AstNode *expr) { if (tv.mode == Addressing_Type) { // // TODO(bill): Handle this correctly #if 0 - i32 entry_index = type_info_index(proc->module->info, tv.type, false); + i32 entry_index = ir_type_info_index(proc->module->info, tv.type, false); if (entry_index >= 0) { return ir_get_type_info_ptr(proc, tv.type); // i32 id = entry_index+1; @@ -7615,7 +7642,7 @@ void ir_init_module(irModule *m, Checker *c) { { // Add type info data { - isize max_type_info_count = m->info->type_info_types.count; + isize max_type_info_count = ir_type_info_count(m->info); String name = str_lit(IR_TYPE_INFO_DATA_NAME); Entity *e = alloc_entity_variable(nullptr, make_token_ident(name), alloc_type_array(t_type_info, max_type_info_count), false); @@ -7774,7 +7801,7 @@ void ir_gen_destroy(irGen *s) { // Type Info stuff // irValue *ir_get_type_info_ptr(irProcedure *proc, Type *type) { - i32 index = cast(i32)type_info_index(proc->module->info, type); + i32 index = cast(i32)ir_type_info_index(proc->module->info, type); // gb_printf_err("%d %s\n", index, type_to_string(type)); irValue *ptr = ir_emit_array_epi(proc, ir_global_type_info_data, index); return ir_emit_bitcast(proc, ptr, t_type_info_ptr); @@ -7837,7 +7864,10 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info continue; } - isize entry_index = type_info_index(info, t); + isize entry_index = ir_type_info_index(info, t, false); + if (entry_index <= 0) { + continue; + } irValue *tag = nullptr; irValue *ti_ptr = ir_emit_array_epi(proc, ir_global_type_info_data, cast(i32)entry_index);