|
@@ -4562,145 +4562,7 @@ void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped) {
|
|
|
map_clear(untyped);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
-void check_parsed_files(Checker *c) {
|
|
|
-#define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0)
|
|
|
-
|
|
|
- TIME_SECTION("map full filepaths to scope");
|
|
|
- add_type_info_type(&c->builtin_ctx, t_invalid);
|
|
|
-
|
|
|
- // Map full filepaths to Scopes
|
|
|
- for_array(i, c->parser->packages) {
|
|
|
- AstPackage *p = c->parser->packages[i];
|
|
|
- Scope *scope = create_scope_from_package(&c->builtin_ctx, p);
|
|
|
- p->decl_info = make_decl_info(scope, c->builtin_ctx.decl);
|
|
|
- string_map_set(&c->info.packages, p->fullpath, p);
|
|
|
-
|
|
|
- if (scope->flags&ScopeFlag_Init) {
|
|
|
- c->info.init_package = p;
|
|
|
- c->info.init_scope = scope;
|
|
|
- }
|
|
|
- if (p->kind == Package_Runtime) {
|
|
|
- GB_ASSERT(c->info.runtime_package == nullptr);
|
|
|
- c->info.runtime_package = p;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- TIME_SECTION("collect entities");
|
|
|
- // Collect Entities
|
|
|
- CheckerContext collect_entity_ctx = make_checker_context(c);
|
|
|
- defer (destroy_checker_context(&collect_entity_ctx));
|
|
|
- for_array(i, c->parser->packages) {
|
|
|
- AstPackage *pkg = c->parser->packages[i];
|
|
|
-
|
|
|
- CheckerContext *ctx = &collect_entity_ctx;
|
|
|
-
|
|
|
- for_array(j, pkg->files) {
|
|
|
- AstFile *f = pkg->files[j];
|
|
|
- string_map_set(&c->info.files, f->fullpath, f);
|
|
|
-
|
|
|
- create_scope_from_file(nullptr, f);
|
|
|
- reset_checker_context(ctx, f);
|
|
|
- check_collect_entities(ctx, f->decls);
|
|
|
- }
|
|
|
-
|
|
|
- pkg->used = true;
|
|
|
- }
|
|
|
-
|
|
|
- TIME_SECTION("import entities");
|
|
|
- check_import_entities(c);
|
|
|
-
|
|
|
- TIME_SECTION("check all global entities");
|
|
|
- check_all_global_entities(c);
|
|
|
-
|
|
|
- TIME_SECTION("init preload");
|
|
|
- init_preload(c);
|
|
|
-
|
|
|
- TIME_SECTION("add global untyped expression to queue");
|
|
|
- add_untyped_expressions(&c->info, &c->info.global_untyped);
|
|
|
-
|
|
|
- CheckerContext prev_context = c->builtin_ctx;
|
|
|
- defer (c->builtin_ctx = prev_context);
|
|
|
- c->builtin_ctx.decl = make_decl_info(nullptr, nullptr);
|
|
|
-
|
|
|
- TIME_SECTION("check procedure bodies");
|
|
|
- check_procedure_bodies(c);
|
|
|
-
|
|
|
- TIME_SECTION("check scope usage");
|
|
|
- for_array(i, c->info.files.entries) {
|
|
|
- AstFile *f = c->info.files.entries[i].value;
|
|
|
- check_scope_usage(c, f->scope);
|
|
|
- }
|
|
|
-
|
|
|
- TIME_SECTION("generate minimum dependency set");
|
|
|
- generate_minimum_dependency_set(c, c->info.entry_point);
|
|
|
-
|
|
|
- TIME_SECTION("check test names");
|
|
|
- check_test_names(c);
|
|
|
-
|
|
|
- TIME_SECTION("calculate global init order");
|
|
|
- // Calculate initialization order of global variables
|
|
|
- calculate_global_init_order(c);
|
|
|
-
|
|
|
- TIME_SECTION("check bodies have all been checked");
|
|
|
- check_unchecked_bodies(c);
|
|
|
-
|
|
|
- TIME_SECTION("add untyped expression values");
|
|
|
- // Add untyped expression values
|
|
|
- for (UntypedExprInfo u = {}; mpmc_dequeue(&c->info.untyped_queue, &u); /**/) {
|
|
|
- GB_ASSERT(u.expr != nullptr && u.info != nullptr);
|
|
|
- if (is_type_typed(u.info->type)) {
|
|
|
- compiler_error("%s (type %s) is typed!", expr_to_string(u.expr), type_to_string(u.info->type));
|
|
|
- }
|
|
|
- add_type_and_value(&c->info, u.expr, u.info->mode, u.info->type, u.info->value);
|
|
|
- }
|
|
|
-
|
|
|
- // TODO(bill): Check for unused imports (and remove) or even warn/err
|
|
|
- // TODO(bill): Any other checks?
|
|
|
-
|
|
|
-
|
|
|
- TIME_SECTION("add type information");
|
|
|
- // Add "Basic" type information
|
|
|
- for (isize i = 0; i < Basic_COUNT; i++) {
|
|
|
- Type *t = &basic_types[i];
|
|
|
- if (t->Basic.size > 0 &&
|
|
|
- (t->Basic.flags & BasicFlag_LLVM) == 0) {
|
|
|
- add_type_info_type(&c->builtin_ctx, t);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- TIME_SECTION("check for type cycles and inline cycles");
|
|
|
- // NOTE(bill): Check for illegal cyclic type declarations
|
|
|
- for_array(i, c->info.definitions) {
|
|
|
- Entity *e = c->info.definitions[i];
|
|
|
- if (e->kind == Entity_TypeName && e->type != nullptr) {
|
|
|
- (void)type_align_of(e->type);
|
|
|
- } else if (e->kind == Entity_Procedure) {
|
|
|
- DeclInfo *decl = e->decl_info;
|
|
|
- ast_node(pl, ProcLit, decl->proc_lit);
|
|
|
- if (pl->inlining == ProcInlining_inline) {
|
|
|
- for_array(j, decl->deps.entries) {
|
|
|
- Entity *dep = decl->deps.entries[j].ptr;
|
|
|
- if (dep == e) {
|
|
|
- error(e->token, "Cannot inline recursive procedure '%.*s'", LIT(e->token.string));
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- TIME_SECTION("add type info for type definitions");
|
|
|
- for_array(i, c->info.definitions) {
|
|
|
- Entity *e = c->info.definitions[i];
|
|
|
- if (e->kind == Entity_TypeName && e->type != nullptr) {
|
|
|
- i64 align = type_align_of(e->type);
|
|
|
- if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) {
|
|
|
- add_type_info_type(&c->builtin_ctx, e->type);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- TIME_SECTION("check deferred procedures");
|
|
|
+void check_deferred_procedures(Checker *c) {
|
|
|
for (Entity *src = nullptr; mpmc_dequeue(&c->procs_with_deferred_to_check, &src); /**/) {
|
|
|
GB_ASSERT(src->kind == Entity_Procedure);
|
|
|
|
|
@@ -4851,6 +4713,172 @@ void check_parsed_files(Checker *c) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+}
|
|
|
+
|
|
|
+void check_unique_package_names(Checker *c) {
|
|
|
+ StringMap<AstPackage *> pkgs = {}; // Key: package name
|
|
|
+ string_map_init(&pkgs, heap_allocator(), 2*c->info.packages.entries.count);
|
|
|
+ defer (string_map_destroy(&pkgs));
|
|
|
+
|
|
|
+ for_array(i, c->info.packages.entries) {
|
|
|
+ AstPackage *pkg = c->info.packages.entries[i].value;
|
|
|
+ if (pkg->files.count == 0) {
|
|
|
+ continue; // Sanity check
|
|
|
+ }
|
|
|
+
|
|
|
+ String name = pkg->name;
|
|
|
+ auto key = string_hash_string(name);
|
|
|
+ auto *found = string_map_get(&pkgs, key);
|
|
|
+ if (found == nullptr) {
|
|
|
+ string_map_set(&pkgs, key, pkg);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ error(pkg->files[0]->pkg_decl, "Duplicate declaration of 'package %.*s'", LIT(name));
|
|
|
+ error_line("\tA package name must be unique\n"
|
|
|
+ "\tThere is no relation between a package name and the directory that contains it, so they can be completely different\n"
|
|
|
+ "\tA package name is required for link name prefixing to have a consistent ABI\n");
|
|
|
+ error((*found)->files[0]->pkg_decl, "found at previous location");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+void check_parsed_files(Checker *c) {
|
|
|
+#define TIME_SECTION(str) do { if (build_context.show_more_timings) timings_start_section(&global_timings, str_lit(str)); } while (0)
|
|
|
+
|
|
|
+ TIME_SECTION("map full filepaths to scope");
|
|
|
+ add_type_info_type(&c->builtin_ctx, t_invalid);
|
|
|
+
|
|
|
+ // Map full filepaths to Scopes
|
|
|
+ for_array(i, c->parser->packages) {
|
|
|
+ AstPackage *p = c->parser->packages[i];
|
|
|
+ Scope *scope = create_scope_from_package(&c->builtin_ctx, p);
|
|
|
+ p->decl_info = make_decl_info(scope, c->builtin_ctx.decl);
|
|
|
+ string_map_set(&c->info.packages, p->fullpath, p);
|
|
|
+
|
|
|
+ if (scope->flags&ScopeFlag_Init) {
|
|
|
+ c->info.init_package = p;
|
|
|
+ c->info.init_scope = scope;
|
|
|
+ }
|
|
|
+ if (p->kind == Package_Runtime) {
|
|
|
+ GB_ASSERT(c->info.runtime_package == nullptr);
|
|
|
+ c->info.runtime_package = p;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ TIME_SECTION("collect entities");
|
|
|
+ // Collect Entities
|
|
|
+ CheckerContext collect_entity_ctx = make_checker_context(c);
|
|
|
+ defer (destroy_checker_context(&collect_entity_ctx));
|
|
|
+ for_array(i, c->parser->packages) {
|
|
|
+ AstPackage *pkg = c->parser->packages[i];
|
|
|
+
|
|
|
+ CheckerContext *ctx = &collect_entity_ctx;
|
|
|
+
|
|
|
+ for_array(j, pkg->files) {
|
|
|
+ AstFile *f = pkg->files[j];
|
|
|
+ string_map_set(&c->info.files, f->fullpath, f);
|
|
|
+
|
|
|
+ create_scope_from_file(nullptr, f);
|
|
|
+ reset_checker_context(ctx, f);
|
|
|
+ check_collect_entities(ctx, f->decls);
|
|
|
+ }
|
|
|
+
|
|
|
+ pkg->used = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ TIME_SECTION("import entities");
|
|
|
+ check_import_entities(c);
|
|
|
+
|
|
|
+ TIME_SECTION("check all global entities");
|
|
|
+ check_all_global_entities(c);
|
|
|
+
|
|
|
+ TIME_SECTION("init preload");
|
|
|
+ init_preload(c);
|
|
|
+
|
|
|
+ TIME_SECTION("add global untyped expression to queue");
|
|
|
+ add_untyped_expressions(&c->info, &c->info.global_untyped);
|
|
|
+
|
|
|
+ CheckerContext prev_context = c->builtin_ctx;
|
|
|
+ defer (c->builtin_ctx = prev_context);
|
|
|
+ c->builtin_ctx.decl = make_decl_info(nullptr, nullptr);
|
|
|
+
|
|
|
+ TIME_SECTION("check procedure bodies");
|
|
|
+ check_procedure_bodies(c);
|
|
|
+
|
|
|
+ TIME_SECTION("check scope usage");
|
|
|
+ for_array(i, c->info.files.entries) {
|
|
|
+ AstFile *f = c->info.files.entries[i].value;
|
|
|
+ check_scope_usage(c, f->scope);
|
|
|
+ }
|
|
|
+
|
|
|
+ TIME_SECTION("generate minimum dependency set");
|
|
|
+ generate_minimum_dependency_set(c, c->info.entry_point);
|
|
|
+
|
|
|
+ TIME_SECTION("check test names");
|
|
|
+ check_test_names(c);
|
|
|
+
|
|
|
+ TIME_SECTION("calculate global init order");
|
|
|
+ // Calculate initialization order of global variables
|
|
|
+ calculate_global_init_order(c);
|
|
|
+
|
|
|
+ TIME_SECTION("check bodies have all been checked");
|
|
|
+ check_unchecked_bodies(c);
|
|
|
+
|
|
|
+ TIME_SECTION("add untyped expression values");
|
|
|
+ // Add untyped expression values
|
|
|
+ for (UntypedExprInfo u = {}; mpmc_dequeue(&c->info.untyped_queue, &u); /**/) {
|
|
|
+ GB_ASSERT(u.expr != nullptr && u.info != nullptr);
|
|
|
+ if (is_type_typed(u.info->type)) {
|
|
|
+ compiler_error("%s (type %s) is typed!", expr_to_string(u.expr), type_to_string(u.info->type));
|
|
|
+ }
|
|
|
+ add_type_and_value(&c->info, u.expr, u.info->mode, u.info->type, u.info->value);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ TIME_SECTION("add type information");
|
|
|
+ // Add "Basic" type information
|
|
|
+ for (isize i = 0; i < Basic_COUNT; i++) {
|
|
|
+ Type *t = &basic_types[i];
|
|
|
+ if (t->Basic.size > 0 &&
|
|
|
+ (t->Basic.flags & BasicFlag_LLVM) == 0) {
|
|
|
+ add_type_info_type(&c->builtin_ctx, t);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ TIME_SECTION("check for type cycles and inline cycles");
|
|
|
+ // NOTE(bill): Check for illegal cyclic type declarations
|
|
|
+ for_array(i, c->info.definitions) {
|
|
|
+ Entity *e = c->info.definitions[i];
|
|
|
+ if (e->kind == Entity_TypeName && e->type != nullptr) {
|
|
|
+ (void)type_align_of(e->type);
|
|
|
+ } else if (e->kind == Entity_Procedure) {
|
|
|
+ DeclInfo *decl = e->decl_info;
|
|
|
+ ast_node(pl, ProcLit, decl->proc_lit);
|
|
|
+ if (pl->inlining == ProcInlining_inline) {
|
|
|
+ for_array(j, decl->deps.entries) {
|
|
|
+ Entity *dep = decl->deps.entries[j].ptr;
|
|
|
+ if (dep == e) {
|
|
|
+ error(e->token, "Cannot inline recursive procedure '%.*s'", LIT(e->token.string));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ TIME_SECTION("add type info for type definitions");
|
|
|
+ for_array(i, c->info.definitions) {
|
|
|
+ Entity *e = c->info.definitions[i];
|
|
|
+ if (e->kind == Entity_TypeName && e->type != nullptr) {
|
|
|
+ i64 align = type_align_of(e->type);
|
|
|
+ if (align > 0 && ptr_set_exists(&c->info.minimum_dependency_set, e)) {
|
|
|
+ add_type_info_type(&c->builtin_ctx, e->type);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ TIME_SECTION("check deferred procedures");
|
|
|
+ check_deferred_procedures(c);
|
|
|
|
|
|
TIME_SECTION("check entry point");
|
|
|
if (build_context.build_mode == BuildMode_Executable && !build_context.no_entry_point && build_context.command_kind != Command_test) {
|
|
@@ -4875,32 +4903,7 @@ void check_parsed_files(Checker *c) {
|
|
|
}
|
|
|
|
|
|
TIME_SECTION("check unique package names");
|
|
|
- {
|
|
|
- StringMap<AstPackage *> pkgs = {}; // Key: package name
|
|
|
- string_map_init(&pkgs, heap_allocator(), 2*c->info.packages.entries.count);
|
|
|
- defer (string_map_destroy(&pkgs));
|
|
|
-
|
|
|
- for_array(i, c->info.packages.entries) {
|
|
|
- AstPackage *pkg = c->info.packages.entries[i].value;
|
|
|
- if (pkg->files.count == 0) {
|
|
|
- continue; // Sanity check
|
|
|
- }
|
|
|
-
|
|
|
- String name = pkg->name;
|
|
|
- auto key = string_hash_string(name);
|
|
|
- auto *found = string_map_get(&pkgs, key);
|
|
|
- if (found == nullptr) {
|
|
|
- string_map_set(&pkgs, key, pkg);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- error(pkg->files[0]->pkg_decl, "Duplicate declaration of 'package %.*s'", LIT(name));
|
|
|
- error_line("\tA package name must be unique\n"
|
|
|
- "\tThere is no relation between a package name and the directory that contains it, so they can be completely different\n"
|
|
|
- "\tA package name is required for link name prefixing to have a consistent ABI\n");
|
|
|
- error((*found)->files[0]->pkg_decl, "found at previous location");
|
|
|
- }
|
|
|
- }
|
|
|
+ check_unique_package_names(c);
|
|
|
|
|
|
TIME_SECTION("type check finish");
|
|
|
|