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:
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