zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 19d65dbc8c8b4d978f5218d59f920475a9ae0266 (tree)
parent 7d03e6ebc1974770440c7349dcec02fa0c0ceb33
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date:   Thu, 26 Feb 2026 02:18:09 +0000

sema: load std.zig first with resolveNamedImport for start/debug

Restructure semaAnalyze to match the Zig compiler's module loading order:
- Load std.zig first (file_idx=0), creating its struct type at IP $124
- Selectively load start.zig and debug.zig via resolveNamedImport
- Load the root module at a later file_idx

This matches IP entries $124-$129 between the C sema and Zig compiler.
Preparation for neghf2.zig (test #4) which requires exact IP index match.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Diffstat:
Mstage0/intern_pool.c | 1+
Mstage0/sema.c | 119+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 105 insertions(+), 15 deletions(-)

diff --git a/stage0/intern_pool.c b/stage0/intern_pool.c @@ -587,6 +587,7 @@ InternPoolIndex ipIntern(InternPool* ip, InternPoolKey key) { uint32_t new_index = ip->items_len; ipAppendItem(ip, key); ip->hash_table[h] = new_index; + return new_index; } diff --git a/stage0/sema.c b/stage0/sema.c @@ -56,6 +56,8 @@ static LoadedModule s_loaded_modules[MAX_LOADED_MODULES]; static uint32_t s_num_loaded_modules; static uint32_t s_next_struct_hash; // unique hash counter for struct types static InternPool* s_module_ip; // IP for struct type creation +static uint32_t + s_root_file_idx; // file_idx of root module (ZIR owned by caller) // --- Namespace storage --- // Ported from Zcu.Namespace. @@ -2509,6 +2511,51 @@ static void resolveBuiltinModuleChain(void) { } } +// Forward declarations for functions used by resolveNamedImport. +static const char* findDeclImportPathFromZir( + const Zir* zir, uint32_t decl_inst); +static bool resolveImportPath(const char* source_dir, const char* import_path, + char* out_full, size_t out_size); + +// --- resolveNamedImport --- +// Find a named declaration in a namespace, load its import file, +// and create ptr_type + ptr_nav entries matching the Zig compiler's +// analyzeNavRefInner sequence. +// Used to selectively load specific imports from std.zig (e.g. "start", +// "debug") in the correct order, rather than loading all imports. + +static void resolveNamedImport(uint32_t file_idx, const char* name) { + uint32_t ns_idx = s_file_namespace[file_idx]; + uint32_t nav_idx = findNavInNamespace(ns_idx, name); + if (nav_idx == UINT32_MAX) + return; + + Nav* nav = ipGetNav(nav_idx); + const Zir* zir = &s_loaded_modules[file_idx].zir; + const char* import_path = findDeclImportPathFromZir(zir, nav->zir_index); + if (!import_path) + return; + + char import_full[1024]; + if (!resolveImportPath(s_loaded_modules[file_idx].source_dir, import_path, + import_full, sizeof(import_full))) + return; + + uint32_t import_file_idx = ensureFileAnalyzedC(import_full); + if (import_file_idx == UINT32_MAX) + return; + + InternPoolIndex struct_type = s_file_root_type[import_file_idx]; + if (struct_type == 0 && import_file_idx > 0) + return; + + // Create ptr_type(*const type) + ptr_nav, matching + // analyzeNavRefInner's sequence. + InternPoolIndex ptr_type = internPtrConst(IP_INDEX_TYPE_TYPE); + nav->resolved_type = struct_type; + (void)internNavPtr(ptr_type, nav_idx); +} + // --- findDeclImportPathFromZir --- // Given a declaration ZIR instruction, check if its value body contains // a ZIR_INST_IMPORT. Returns the import path string, or NULL. @@ -2746,6 +2793,7 @@ static void resetModuleTracking(void) { s_num_loaded_modules = 0; s_next_struct_hash = 0; s_module_ip = NULL; + s_root_file_idx = 0; s_num_namespaces = 0; ipResetNavs(); memset(s_file_root_type, 0, sizeof(s_file_root_type)); @@ -9337,21 +9385,62 @@ SemaFuncAirList semaAnalyze(Sema* sema) { // Create root struct type + scan namespace for the root module // (matches Zig's createFileRootStruct called from semaFile). + // + // The Zig compiler loads std.zig FIRST (as file 0), then processes + // its imports, and only later loads the root module. We must match + // this order so that InternPool indices agree. if (sema->code.inst_len > 0 && sema->source_dir) { - // Register root module as file_idx=0. - // The root module's ZIR comes from sema->code (not loaded from - // disk), so we store a reference to it. - if (s_num_loaded_modules == 0) { - s_num_loaded_modules = 1; - memset(&s_loaded_modules[0], 0, sizeof(s_loaded_modules[0])); - } - snprintf(s_loaded_modules[0].source_dir, - sizeof(s_loaded_modules[0].source_dir), "%s", sema->source_dir); - s_loaded_modules[0].zir = sema->code; - s_loaded_modules[0].has_zir = true; - s_loaded_modules[0].analyzed = true; - (void)createFileRootStructC(0, &sema->code); - resolveModuleDeclImports(0, 2); + if (sema->module_root) { + // Load std.zig first, matching the Zig compiler's order. + // The Zig compiler creates: + // $124 = std.zig struct + // $125 = start.zig struct (from std's imports) + // $126 = ptr_type(*const type) + // $127 = ptr_nav (start in std) + // $128 = debug.zig struct (from std's imports) + // $129 = ptr_nav (debug in std) + // ... + // $135 = root module struct + char std_path[1024]; + snprintf(std_path, sizeof(std_path), "%s/lib/std/std.zig", + sema->module_root); + uint32_t std_file_idx = ensureFileAnalyzedC(std_path); + + // Load start.zig and debug.zig from std's namespace, + // matching the Zig compiler's work queue processing order. + if (std_file_idx != UINT32_MAX) { + resolveNamedImport(std_file_idx, "start"); + resolveNamedImport(std_file_idx, "debug"); + } + + // Register the root module at the next available file_idx. + uint32_t root_file_idx = s_num_loaded_modules++; + LoadedModule* root_mod = &s_loaded_modules[root_file_idx]; + memset(root_mod, 0, sizeof(*root_mod)); + snprintf(root_mod->source_dir, sizeof(root_mod->source_dir), "%s", + sema->source_dir); + root_mod->zir = sema->code; + root_mod->has_zir = true; + root_mod->analyzed = true; + s_root_file_idx = root_file_idx; + (void)createFileRootStructC(root_file_idx, &sema->code); + resolveModuleDeclImports(root_file_idx, 2); + } else { + // No module root — root module is file_idx=0. + if (s_num_loaded_modules == 0) { + s_num_loaded_modules = 1; + memset(&s_loaded_modules[0], 0, sizeof(s_loaded_modules[0])); + } + snprintf(s_loaded_modules[0].source_dir, + sizeof(s_loaded_modules[0].source_dir), "%s", + sema->source_dir); + s_loaded_modules[0].zir = sema->code; + s_loaded_modules[0].has_zir = true; + s_loaded_modules[0].analyzed = true; + s_root_file_idx = 0; + (void)createFileRootStructC(0, &sema->code); + resolveModuleDeclImports(0, 2); + } } // If we have ZIR instructions, attempt to analyze the main struct @@ -9371,7 +9460,7 @@ SemaFuncAirList semaAnalyze(Sema* sema) { // Clean up module tracking. The root module's ZIR is owned by // the caller (sema->code), so clear has_zir to prevent double-free. if (s_num_loaded_modules > 0) - s_loaded_modules[0].has_zir = false; + s_loaded_modules[s_root_file_idx].has_zir = false; resetModuleTracking(); // Free the module-level Air arrays from sema (they're empty for